C++标准是否规定函数模板实例化副作用的可见时机?
我要问的不是“函数模板何时实例化?”,而是该实例化的副作用何时可见?
实例化的副作用以友元注入为例,代码如下(Clang、GCC、MSVC编译结果一致):
template<int N> struct FriendIndex { friend constexpr bool Get(FriendIndex); }; template<int N, bool val> struct FriendInjector { friend constexpr bool Get(FriendIndex<N>) { return true; } }; template <bool val> auto InstantSideEffect() { (void)FriendInjector<0, val>{}; return 0; } template <bool val> int DelayedSideEffect() { (void)FriendInjector<1, val>{}; return 0; } int dummy0 = InstantSideEffect<true>(); // 编译成功 static_assert(Get(FriendIndex<0>{}), ""); int dummy1 = DelayedSideEffect<true>(); // 编译失败:Get(FriendIndex<1>)不是常量表达式 static_assert(Get(FriendIndex<1>{}), "");
这段代码的现象是:
- 实例化
InstantSideEffect<true>()后,constexpr友元函数Get(FriendIndex<0>)的定义立即可见,能通过后续的static_assert; - 实例化
DelayedSideEffect<true>()后,Get(FriendIndex<1>)的定义无法立即可见,导致static_assert编译失败。
两个函数仅返回值类型不同:InstantSideEffect()返回auto,DelayedSideEffect()返回int。我查阅了C++标准,想确认auto是否会影响这类副作用的可见时机。
C++14标准草案(7.1.6.4 [dcl.spec.auto]/12)中提到:
Return type deduction for a function template with a placeholder in its declared type occurs when the definition is instantiated even if the function body contains a return statement with a non-type-dependent operand. [ Note: Therefore, any use of a specialization of the function template will cause an implicit instantiation. Any errors that arise from this instantiation are not in the immediate context of the function type and can result in the program being ill-formed. — end note ]
这段说明指出auto会影响函数模板特化的实例化,还可能影响SFINAE,但我没在标准里找到关于副作用可见时机的明确规定。
我的疑问是:
- 标准中是否有涉及友元注入这类副作用可见时机的内容?
- 还是说三大编译器对返回
auto的函数模板立即暴露友元注入副作用只是巧合,未来可能改变行为?
内容的提问来源于stack exchange,提问作者Joshua Maiche

