静态断言和SFINAE

时间:2013-04-30 14:58:19

标签: c++ c++11 sfinae static-assert

考虑一下:

template <typename T>
struct hash
{
     static_assert(false,"Not implemented.");
};

struct unhashable {};

template <typename T>
auto test(const T &t) -> decltype((*(hash<T> const *)nullptr)(t),int);

void test(...);

int main()
{
    std::cout << std::is_same<decltype(test(std::declval<unhashable>())),void>::value;
}

除了明显缺少标题之外,还应编译吗?

换句话说,我问的是,在推断重载函数模板的返回值时,是否要求在尾随的decltype内触发静态断言失败来暂停编译,或者是否只是要丢弃重载。

在gcc 4.7上,编译失败。我很积极,虽然这将在gcc 4.8中编译好(但在此刻无法检查)。谁是对的?

2 个答案:

答案 0 :(得分:14)

编译必须在任何兼容的编译器中失败。

SFINAE规则基于声明而非定义。 (对不起,如果我在这里使用了错误的术语。)我的意思是:

对于类/结构:

template < /* substitution failures here are not errors */ >
struct my_struct {
    // Substitution failures here are errors.
};

对于一个功能:

template </* substitution failures here are not errors */>
/* substitution failures here are not errors */
my_function( /* substitution failures here are not errors */) {
    /* substitution failures here are errors */
}

此外,给定模板参数集的结构/函数的不存在也受SFINAE规则的约束。

现在static_assert只能出现在替换失败错误的区域,因此,如果它触发,您将收到编译错误。

例如,以下是enable_if的错误实现:

// Primary template (OK)
template <bool, typename T>
struct enable_if;

// Specialization for true (also OK)
template <typename T>
struct enable_if<true, T> {
    using type = T;
};

// Specialization for false (Wrong!)
template <typename T>
struct enable_if<false, T> {
    static_assert(std::is_same<T, T*>::value, "No SFINAE here");
    // The condition is always false.
    // Notice also that the condition depends on T but it doesn't make any difference.
};

然后试试这个

template <typename T>
typename enable_if<std::is_integral<T>::value, int>::type
test(const T &t);

void test(...);

int main()
{
    std::cout << std::is_same<decltype(test(0)), int>::value << std::endl; // OK
    std::cout << std::is_same<decltype(test(0.0)), void>::value << std::endl; // Error: No SFINAE Here
}

如果删除enable_if的{​​{1}}专精,则代码会编译并输出

false

答案 1 :(得分:6)

  

在gcc 4.7上,编译失败。我很积极,虽然这将在gcc 4.8中编译好(但在此刻无法检查)。谁是对的?

静态断言中的条件不依赖于任何模板参数。因此,编译器可以在解析模板时立即将其评估为false,并意识到断言应该触发 - 无论您是否实际在其他地方实例化模板。

任何编译器都应如此。

相关问题