SFINAE,演绎与实例化

Edw*_*nge 6 c++ standards

这段代码无法在大多数编译器中编译,但起初我直观地期望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排除?

K-b*_*llo 2

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