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.