【发布时间】:2012-12-31 06:10:41
【问题描述】:
这段代码在大多数编译器中都无法编译,但起初我直觉地希望 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 排除?
【问题讨论】:
-
我认为这应该在 C++11 中失败,而不是在 C++03 中。 SFINAE 规则(或者更确切地说是措辞)在 C++11 中略有改变。