这段代码无法在大多数编译器中编译,但起初我直觉地希望 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
并有一个类型,如果T
有一个,如果没有,则没有......但是以任何一种方式实例化都没有错误: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 被正确地实例化并且格式正确,但它内部根本没有“类型”定义,这意味着尝试实例化它的模板由于替换而失败。
基本上我想知道标准中的哪些内容指定了我正在目睹的行为。我尝试过的每个编译器都会抱怨,甚至是喜剧。我认为他们这样做是正确的,我只是不完全确定为什么。
那么,专家们......这是什么?为什么类型的实例化,即使在 f() 中的推导上下文中也会导致错误而不是 SFINAE 排除?