C++ constexpr if和static_断言
已经,在C++17的轨道上。它似乎很有用(并且可以取代SFINAE的使用),但是关于C++ constexpr if和static_断言,c++,templates,constexpr,c++17,static-assert,C++,Templates,Constexpr,C++17,Static Assert,已经,在C++17的轨道上。它似乎很有用(并且可以取代SFINAE的使用),但是关于static\u 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-f
static\u 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
}
编辑:我用例子和更详细的解释来保存这个自我回答,解释导致这个问题的误解。T.C.的简短回答就足够了
在重新阅读了该提案并在static_assert上发表声明后,我得出结论,我的担忧被误导了。首先,这里的重点应该是模板定义
畸形的;模板定义不需要诊断
如果模板被实例化,任何静态断言都会按预期触发。这大概与我引用的说法很吻合:
。。。丢弃的语句不会实例化
这对我来说有点模糊,但我认为这意味着在丢弃的语句中出现的模板将不会被实例化。其他代码
但是必须在语法上有效。因此,当实例化包含静态断言的模板时,丢弃的if constexpr
子句中的静态断言(F)
,[其中F为false,字面上或constexpr值]。或者(不需要,由编译器决定)已经在声明中,如果已知它总是错误的
例如:()
#包括
模板
constexpr void some_library_foo(){
静态断言(std::is\u same::value);
}
模板
constexpr void other_library_bar(){
静态断言(std::is\u same::value);
}
模板
constexpr void buzz(){
//此模板格式错误,(无效)无需诊断,
//因为没有可以使它有效的T
//在T.C.的回答中)。
//这也意味着这两种武器都不需要开火,但是
//在
//至少在buzz被实例化时。
静态断言(!std::is_same::value);
static_assert(false);//是否已在声明中激发
//最新版本的叮当声
}
模板
void g(){
if constexpr(IntCase){
一些图书馆;
//即使在if constexpr内,两个静态断言都将触发:
static_assert(!IntCase);//如果需要,则需要格式错误的诊断
//这是真的
static_assert(IntCase);//如果需要,则需要格式错误的诊断
//这个案子是假的
//但是,不要这样做:
static_assert(false);//格式错误,无需诊断,
//原因与buzz()相同。
}否则{
其他_库_栏();
}
}
int main(){
g();
g();
//g();//格式错误,需要诊断
//g();//格式错误,需要诊断
}
static\u assert
上的标准文本非常短。在standardese中,这是一种使用diagnostic使程序格式错误的方法(正如@immibis也指出的):
7.6。。。如果如此转换时表达式的值为true,则声明无效。否则,程序格式不正确,并且
产生的诊断信息(1.4)应包括
字符串文字,如果提供了一个
这是关于模板的一个完善的规则-这一规则允许编译器诊断template void f(){return 1;}
。新的更改以粗体显示:
如果出现以下情况,程序格式不正确,无需诊断:
- 无法为模板或子语句生成有效的专门化
语句中的
constepr if
语句([stmt.if])
模板且模板未实例化,或
- [……]
无法为包含static\u assert
的模板生成有效的专门化,该模板的条件是非依赖的,其计算结果为false
,因此程序是格式错误的NDR
static\u assert
s与至少一种类型的计算结果为true
的相关条件不受影响。您自己的答案,可能还有T.C.的答案都不太正确
首先,“即使在范围内,如果constexpr
,两个静态断言都将触发”这句话是不正确的。因为if constexpr
条件取决于模板参数,所以它们不会更改。
您可以看到,如果注释掉示例代码中的static\u assert(false)
语句和buzz()
的定义:static\u assert(!IntCase)
将不会触发,它将编译
此外,像这样的东西总是会有值或!std::在丢弃的constexpr中是否相同(且没有任何效果),如果,,即使没有T
它们的计算结果为真
我认为“无法生成有效的专门化”是标准中的糟糕措辞(除非CPPPreference是错误的;那么T.C.将是正确的)。它应该说“可以产生”,并进一步澄清“可以”的含义
这与以下问题有关:AlwaysFalse::value
和!std::在这个上下文中是相同的吗(这就是对这个答案的评论)。
我认为它们是,因为它是“can”而不是“can”,并且在实例化时对所有类型都是错误的。
std::is_same
和非标准包装器之间的关键区别在于后者在理论上可以是专门化的(感谢cigien指出这一点并提供链接)
格式错误的NDR与否的问题也取决于模板是否实例化,这一点非常清楚。C++20使成为静态的_
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>();
}
#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-formed, (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-formed diagnostic required if
// IntCase is true
static_assert(IntCase) ; // ill-formed diagnostic required if
// IntCase is false
// However, don't do this:
static_assert(false) ; // ill-formed, 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-formed, diagnostic required
//g<float,true>(); // ill-formed, diagnostic required
}
template<typename T>
void g()
{
if constexpr (case_1)
// ...
else if constexpr (case_2)
// ...
else
[]<bool flag = false>()
{static_assert(flag, "no match");}();
}