Reputation: 1699
From cppreference:
When the noexcept-specification of a function template specialization is needed, but hasn't yet been instantiated, the dependent names are looked up and any templates used in the expression are instantiated as if for the declaration of the specialization.
Could someone provide some example(s) of this?
What names can be looked up here (is there necessarily ADL involved, or is it e.g. just plain dependent type names that have to be looked up themselves)?
I have a hard time understanding what the above means.
Upvotes: 2
Views: 102
Reputation: 302922
It basically means that when the noexcept-specification is needed (which is a specific term), it is instantiated. And when it's instantiated, it's instantiated in the same way that function template declarations are instantiated - including everything that has to happen for that.
The cppreference example has:
template<class T> T f() noexcept(sizeof(T) < 4);
decltype(f<void>()) *p; // error
Even though we're not evaluating f
, the noexcept-specification of it is needed (because f
is selected by overload resolution and would be odr-used if it were evaluated). So at that point it is instantiated. But that instantiation is an error because sizeof(void)
is ill-formed.
On the other hand, this slightly modified version is ok:
template<class T> T f(int);
template<class T> T f() noexcept(sizeof(T) < 4);
decltype(f<void>(1)) *p; // ok
We never instantiate f()
's noexcept-specification because it is not needed.
There is nothing special with respect to name lookup. It's just the normal template rules apply, so:
struct N {
struct X { };
void h(X);
}
void h(int) noexcept;
template<class T> void g(T t) noexcept(noexcept(h(t))
When the noexcept-specification of g
is needed, that's to instantiate h(t)
- which may or may not perform ADL as usual. noexcept(g(0))
would be true
, but noexcept(g(N::X{}))
would be false
.
Additionally, any relevant templates are only instantiated when they are needed. So if we had:
template<class T> struct X;
template<class T> T f() noexcept(X<T>::value);
template<class T> T f(int);
X<T>
will only be instantiated when that noexcept-specification is needed, not before. So decltype(f<int>(0))
will not try to instantiate X<int>
, but decltype(f<int>())
would be a hard-error because X<int>
is an incomplete type so X<int>::value
is ill-formed.
Upvotes: 1