这段代码无法在大多数编译器中编译,但起初我直观地期望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()); }
Run Code Online (Sandbox Code Playgroud)
我可以通过至少两种方式解决问题:
1)将"metafun"f()的定义更改为:
template < typename T >
typename T::type f(T) {}
2)定义"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 };
Run Code Online (Sandbox Code Playgroud)
在查看14.8.2(C++ 03)时,我认为它确切地说明了SFINAE可以应用的条件.有没有更好的地方看?在已经推断出的模板的实例化中失败,即使在扣除另一个模板时,也不会包含在此列表中.
我用来解释造成这种非法行为的另一个方向是,a_metafun的演绎已经发生,其内部的实例化是导致错误的原因.SFINAE在实例化期间不适用,但仅在扣除期间适用,或者我错在那里?但是在第二种情况下,a_metafun正确,并且格式良好地实例化,但它内部没有"类型"定义,这意味着试图实例化它的模板由于替换而失败.
基本上我想知道标准中的内容指定了我正在目击的行为.我试过的每个编译器都会抱怨,甚至是冒险.我认为这样做是正确的,我只是不确定为什么.
所以,专家......什么是什么?为什么类型的实例化,即使在f()中的演绎语境中导致错误而不是SFINAE排除?
SFINAE不会在那里保护你,错误发生在类型推导之后。但是,这应该有效:
template < typename T, typename Type = typename T::type >
struct a_metafun { typedef Type type; };
Run Code Online (Sandbox Code Playgroud)
通过访问T::type默认模板参数,我们会在替换时发生这种情况,此时SFINAE就会启动。
编辑:经过更多思考,我不确定为什么您当前的实施失败。我认为是因为a_metafun 有一个成员类型type,导致编译错误;如果根本a_metafun没有成员类型,情况就会有所不同。type