constexpr if和static_assert

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (271)

P0292R1constexpr if已经包括在内,在C++17的轨道上。这似乎很有用(也可以取代SFINAE的使用),但对static_assert存在畸形,无需诊断假树枝吓到我了:

Disarming static_assert declarations in the non-taken branch of a
constexpr if is not proposed.

void f() {
  if constexpr (false)
    static_assert(false);   // ill-formed
}

template<class T>
void g() {
  if constexpr (false)
    static_assert(false);   // ill-formed; no 
               // diagnostic required for template definition
}

我认为完全禁止在constexpr中使用static_assert if(至少是false / non-taken分支,但实际上这意味着这不是一个安全或有用的事情)。

标准文本是如何产生的? 我发现提案中没有提到static_assert,C ++ 14 constexpr函数允许static_assert(详见cppreference:constexpr)。

它是否隐藏在这个新句子(6.4.1之后)?*

当模板实体中出现constexpr if语句时,在实例化封闭模板或通用lambda期间,不会实例化丢弃的语句。

从那里开始,我认为它也是被禁止的,不需要诊断,就可以调用其他在调用图的某个地方可能调用static_assert的constexpr(模板)函数。

这段代码在没有警告的情况下编译(clanghead 3.9.0),但据我所知畸形不需要诊断。有效还是无效?

template< typename T>
constexpr void other_library_foo(){
    static_assert(std::is_same<T,int>::value);
}

template<class T>
void g() {
  if constexpr (false)
    other_library_foo<T>(); 
}

int main(){
    g<float>();
    g<int>();
}
提问于
用户回答回答于

这就是为模板建立一个完善的规则 - 允许编译器诊断模板的相同规则<class> void f(){return 1;} [temp.res] / 8以新的粗体显示:

  该程序不合格,不需要诊断,如果:

  • 对于模板中的constexpr if语句([stmt.if])的模板或子语句,不能生成有效的特化,并且该模板未被实例化,或者
  • [...]

对于包含static_assert的模板,如果条件是非依赖的,并且计算结果为false,那么不会生成有效的特化,所以程序是不合格的NDR。

对于至少一个类型可以评估为true的依赖条件的static_assert不受影响。

用户回答回答于

这对我来说有点含糊,但我认为这意味着在放弃语句中出现的模板将不会被实例化。 其他代码必须在语法上有效。 因此,当包含static_assert的模板被实例化时,如果constexpr子句中的static_assert(F),[其中F是false,字面或constexpr值]将仍然“咬”。 或者(不需要,在编译器的支持下)已经在声明中,如果已知它总是假的。

例子:(现场演示)

#include <type_traits>

template< typename T>
constexpr void some_library_foo(){
    static_assert(std::is_same<T,int>::value);
}

template< typename T>
constexpr void other_library_bar(){
    static_assert(std::is_same<T,float>::value);
}

template< typename T>
constexpr void buzz(){
    // This template is ill-formated, (invalid) no diagnostic required,
    // since there are no T which could make it valid. (As also mentioned
    // in the answer by T.C.).
    // That also means that neither of these are required to fire, but
    // clang does (and very likely all compilers for similar cases), at
    // least when buzz is instantiated.
    static_assert(! std::is_same<T,T>::value);
    static_assert(false); // does fire already at declaration
                          // with latest version of clang
}

template<class T, bool IntCase>
void g() {
  if constexpr (IntCase){
    some_library_foo<T>();

    // Both two static asserts will fire even though within if constexpr:
    static_assert(!IntCase) ;  // ill-formated diagnostic required if 
                              // IntCase is true
    static_assert(IntCase) ; // ill-formated diagnostic required if 
                              // IntCase is false

    // However, don't do this:
    static_assert(false) ; // ill-formated, no diagnostic required, 
                           // for the same reasons as with buzz().

  } else {
    other_library_bar<T>();
  }      
}

int main(){
    g<int,true>();
    g<float,false>();

    //g<int,false>(); // ill-formated, diagnostic required
    //g<float,true>(); // ill-formated, diagnostic required
}

标准文本static_assert非常短。在标准中,这是制作程序的一种方式畸形与诊断:

7.6 ...如果转换后表达式的值为true,则声明不起作用。 否则,程序是不合格的,所得到的诊断消息(1.4)应包括字符串文本(如果提供的话)...

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励