如果条件为真,我想在非 constexpr 时引发编译时错误,例如:
if constexpr(condition1){
...
} else if constexpr (condition2) {
....
} else if constexpr (condition3) {
....
} else {
// I want the else clause never taken. But I heard the code below is not allowed
static_assert(false);
}
// I'd rather not repeat the conditions again like this:
static_assert(condition1 || condition2 || condition3);
您必须使废弃的语句依赖于模板参数
template <class...> constexpr std::false_type always_false{};
if constexpr(condition1){
...
} else if constexpr (condition2) {
....
} else if constexpr (condition3) {
....
} else {
static_assert(always_false<T>);
}
之所以如此,是因为
[temp.res]/8 - 程序格式错误,无需诊断,如果
无法为模板或模板内
语句的子语句生成有效的专业化,并且模板未实例化,或者...
constexpr if
这是来自 cppreference.com 的解决方法,即使用依赖于类型的表达式。
注意:对于每个可能的专业化,被丢弃的语句都不能是格式错误的:
此类包罗万象的语句的常见解决方法是始终为 false 的类型相关表达式:
例如
template<class T> struct dependent_false : std::false_type {};
然后
static_assert(dependent_false<T>::value);
使用 C++23,这个问题的答案发生了变化。论文P2593:允许 static_assert(false) 已在 2023-02 Issaquah 会议 上被接受。我们现在可以使用OP想要使用的习语。
我们可以从接受的措辞中看到,dcl.pre p10已被修改,因此
static_assert
在模板定义上下文中不起作用,并且temp.res p6已被修改,因此不再如果 static_assert
所有专业都失败,则格式错误,无需诊断。
还添加了以下示例:
template <class T>
void f(T t) {
if constexpr (sizeof(T) == sizeof(int)) {
use(t);
} else {
static_assert(false, "must be int-sized");
}
}
void g(char c) {
f(0); // OK
f(c); // error: must be int-sized
}
采取稍微不同的策略...
#include <ciso646>
template<auto x> void something();
template<class...Conditions>
constexpr int which(Conditions... cond)
{
int sel = 0;
bool found = false;
auto elect = [&found, &sel](auto cond)
{
if (not found)
{
if (cond)
{
found = true;
}
else
{
++sel;
}
}
};
(elect(cond), ...);
if (not found) throw "you have a logic error";
return sel;
}
template<bool condition1, bool condition2, bool condition3>
void foo()
{
auto constexpr sel = which(condition1, condition2, condition3);
switch(sel)
{
case 0:
something<1>();
break;
case 1:
something<2>();
break;
case 2:
something<3>();
break;
}
}
int main()
{
foo<false, true, false>();
// foo<false, false, false>(); // fails to compile
}
据我了解,
which
在 constexpr 上下文中求值,这意味着它是合法的,除非程序必须遵循在 constexpr 上下文中非法的代码路径。
对于所有预期的情况,不会采用
throw
路径,因此该函数是合法的。当提供非法输入时,我们会走上格式错误的路径,从而导致编译器错误。
我有兴趣知道从语言律师的角度来看这个解决方案是否严格正确。
它适用于 gcc、clang 和 MSVC。
...或者对于混淆代码的粉丝...
template<class...Conditions>
constexpr int which(Conditions... cond)
{
auto sel = 0;
((cond or (++sel, false)) or ...) or (throw "program is ill-formed", false);
return sel;
}