代码之家  ›  专栏  ›  技术社区  ›  J.Doe

如何断言constexpr if else子句从未发生?

  •  27
  • J.Doe  · 技术社区  · 6 年前

    如果条件为真,我想在非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);
    
    3 回复  |  直到 6 年前
        1
  •  28
  •   Jans    6 年前

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

    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 模板中的语句,模板未实例化,或…

        2
  •  14
  •   songyuanyao    6 年前

    这里有一个解决方法 cppreference.com ,即使用依赖于类型的表达式。

    注意:对于每个可能的专门化,丢弃的语句不能是格式错误的:

    这种catch all语句的常见解决方法是一个依赖于类型的表达式,该表达式始终为false:

    例如

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

    然后

    static_assert(dependent_false<T>::value);
    
        3
  •  2
  •   Richard Hodges    6 年前

    采取稍微不同的策略…

    #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;
    }