6

这段代码无法在大多数编译器中编译,但起初我直觉地希望 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()); }

我至少可以通过两种方式解决这个问题:

  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 };
    

在查看 14.8.2 (C++03) 时,我觉得它准确地指定了 SFINAE 可以应用的条件。有更好的地方看吗?已经推导出的模板的实例化失败,即使在推导另一个模板期间,似乎也不会包含在此列表中。

我用来解释什么是非法的另一个方向是 a_metafun 的推断已经发生,并且它的内部实例化是导致错误的原因。SFINAE 在实例化期间不适用,而仅在演绎期间适用,还是我错了?但是,在第二种情况下, a_metafun 被正确地实例化并且格式正确,但它内部根本没有“类型”定义,这意味着尝试实例化它的模板由于替换而失败。

基本上我想知道标准中的哪些内容指定了我正在目睹的行为。我尝试过的每个编译器都会抱怨,甚至是喜剧。我认为他们这样做是正确的,我只是不完全确定为什么。

那么,专家们......这是什么?为什么类型的实例化,即使在 f() 中的推导上下文中也会导致错误而不是 SFINAE 排除?

4

2 回答 2

4
于 2012-12-31T06:42:18.827 回答
2

SFINAE不会在那里保护你,错误发生类型扣除之后。但是,这应该有效:

template < typename T, typename Type = typename T::type >
struct a_metafun { typedef Type type; };

通过访问T::type默认模板参数,我们可以在替换时发生这种情况,此时SFINAE会启动。

编辑:在考虑了更多之后,我不确定您当前的实施为什么会失败。我认为是因为a_metafun 一个成员类型type,它会导致编译错误;如果a_metafun根本没有成员类型,情况会有所不同type

于 2012-12-31T06:14:09.280 回答