此代码无法在大多数编译器中编译,但起初我直觉地希望 SFINAE 能保护我:
typedef void (*A)();
template < typename T >
struct a_metafun { typedef typename T::type type; };
template < typename T >
typename a_metafun<T>::type f(T) {}
template < typename T>
void f(T(*)()) {}
int main() { f(A()); }
我至少可以通过两种方式解决问题:
将“metafun”f() 的定义更改为:
template < typename T > typename T::type f(T) {}
定义
a_metafun
这样它就可以分析T
并且有一个类型 ifT
有一个,如果没有,则没有……但是无论哪种方式都可以无错误地实例化:BOOST_MPL_HAS_XXX_TRAIT_DEF(type) typedef < template T, bool = has_type<T>::value > struct a_metafun { }; typedef < template T > struct a_metafun<T, true> { typedef typename T::type type };
在查看 14.8.2 (C++03) 时,在我看来它明确指定了 SFINAE 可以应用的条件。有没有更好的地方看?已推导模板的实例化失败,即使是在推导另一个模板的过程中,似乎也不会包含在此列表中。
我解释是什么导致此非法的另一个方向是 a_metafun 的推导已经发生,其内部实例化是导致错误的原因。 SFINAE 在实例化期间不适用,但仅在推导期间适用,或者我错了吗?但在第二种情况下,a_metafun 被正确且格式良好地实例化,但它内部根本没有“类型”定义,这意味着尝试实例化它的模板由于替换而失败。
基本上我想知道标准中的哪些内容指定了我正在目睹的行为。我试过的每个编译器都会提示,甚至是 comeau。我认为他们这样做是正确的,我只是不完全确定为什么。
那么,专家们……什么是什么?为什么类型的实例化,即使在 f() 中的推导上下文中也会导致错误而不是 SFINAE 排除?
最佳答案
在 C++03 规范中,SFINAE 的规则有点模糊,允许编译器作者去任何长度来找到导致 SFINAE 的替换失败。 C++03 的相关文本 §14.8.2/2 说,
-
[...] If a substitution in a template parameter or in the function type of the function template results in an invalid type, type deduction fails [...]
它进一步解释了失败的几个原因,但没有一个真正说明在什么时候替换失败应该被视为 SFINAE。所以我想,您的代码可能在 C++03 中运行良好(也可能无法正常运行,具体取决于编译器作者如何解释文本。无论如何,这让我感到困惑)。
但 C++11 中的措辞已得到改进,消除了模糊性。它在 §14.8.2/8 中说,
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as part of the substitution process. —end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
术语“直接上下文” 很有趣,我认为它适用于您的情况。更具体地说,元函数 a_metafun
中的替换失败不被视为函数类型的“直接上下文”。它在 C++11 中是病式的,在 SFINAE 中不是。
但是,尽管 C++11 引入了短语“直接上下文”以使文本稍微好一点,但该短语的定义仍然不够明确。这是一个活跃的问题:
关于c++ - SFINAE,演绎与实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14098131/