【问题标题】:static_assert not evaluated in template parameter模板参数中未评估 static_assert
【发布时间】:2019-01-04 20:52:49
【问题描述】:

我有这段代码可以判断模板类型是否有foo():

template <typename T, typename = void>
struct has_foo : std::false_type {};

template <typename T>
struct has_foo<T, std::void_t<decltype(std::declval<T&>().foo()) > > : std::true_type {};

template <typename T>
void has_foo_f(){
    static_assert(has_foo<T>::value, "Type does not have foo()."); 
}

然后我有一个bar 函数,它接受一个带有foo 的模板参数:

template<typename T, typename = decltype(has_foo_f<T>())>
void bar(){}

在主文件中,我有一个失败案例:

//Foo does not implement foo(). It should fail!
template<typename T>
class Foo{};

int main()
{
    has_foo_f<Foo<int>>(); //This line fail
    bar<Foo<int>>();       //This line does not fail
}

当我直接调用has_foo_f 时,编译器给了我静态断言错误,这是正确的。 但是,当我调用bar&lt;Foo&lt;int&gt;&gt; 时,编译器成功编译它而没有错误。

为什么会这样?为什么不评估 static_assert?我知道decltype 不需要评估static_assert 来获取类型信息,但static_assert 不是总是在编译时评估吗?

【问题讨论】:

  • 看起来不像decltype(has_foo_f&lt;T&gt;()) 实际上实例化了has_foo_f。我不确定它是否是预期的。直观地说,has_foo_f 的返回类型很明显是void,而无需实例化它。如果将返回类型更改为auto,会发生什么?

标签: c++ templates


【解决方案1】:

decltype 的操作数不会被评估,因此不需要函数定义存在(或返回类型完整),而当在需要函数定义存在的上下文中引用特化时实例化函数模板时。因此,您需要实例化函数模板以在函数体内部进行检查:

template<typename T, auto Dummy = &has_foo_f<T>>
void bar(){}

【讨论】:

  • 谢谢。是否有关于此要求的文档?
  • @texasbruce decltype 的操作数不会被评估并且不需要函数定义存在(或返回类型完整),而在需要函数的上下文中引用特化时实例化函数模板定义存在。
  • 我猜这限制了 static_assert 的用例很多。我以为它可以以某种方式替换std::enable_if,但现在看来它不能。
  • @texasbruce 也许您正在寻找concepts
  • 我是,但不幸的是必须等待完整的编译器支持。感谢您的回答!