c++ 如何Assertconstexpr if else子句永远不会发生?

cclgggtu  于 2023-02-20  发布在  其他
关注(0)|答案(4)|浏览(151)

我想提出一个编译时错误时,非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);
vyswwuz2

vyswwuz21#

必须使丢弃的语句依赖于模板参数

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语句的子语句生成有效的专门化,并且模板未示例化,或者...

mw3dktmi

mw3dktmi2#

下面是www.example.com上的一个变通方法cppreference.com,即使用类型相关的表达式。
注意:对于每一个可能的特殊化,被丢弃的语句不能是病态的:
此类捕获所有语句的常见解决方法是始终为false的类型相关表达式:
例如:

template<class T> struct dependent_false : std::false_type {};

那么

static_assert(dependent_false<T>::value);
toe95027

toe950273#

采取了稍微不同的策略。

#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路径都不会被采用,所以函数是法律的的,当提供非法输入时,我们会沿着格式错误的路径前进,这会导致编译器错误。
我很想知道,从语言律师的Angular 来看,这种解决方案是否严格正确。
它适用于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;
}
t1rydlwq

t1rydlwq4#

在C++23中这个问题的答案改变了。在2023-02 Issaquah meeting中我们已经接受了论文P2593: Allowing static_assert(false)。我们现在可以使用OP想要使用的习惯用法。
我们可以从accepted wording中看到,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
  }

相关问题