constexpr if and static_assert

前端 未结 4 2099
清酒与你
清酒与你 2020-11-27 06:39

P0292R1 constexpr if has been included, on track for C++17. It seems useful (and can replace use of SFINAE), but a comment regarding static_assert being ill

4条回答
  •  情书的邮戳
    2020-11-27 07:38

    Edit: I'm keeping this self-answer with examples and more detailed explanations of the misunderstandings that lead to this questions. The short answer by T.C. is strictly enough.

    After rereading the proposal and on static_assert in the current draft, and I conclude that my worries were misguided. First of all, the emphasis here should be on template definition.

    ill-formed; no diagnostic required for template definition

    If a template is instantiated, any static_assert fire as expected. This presumably plays well with the statement I quoted:

    ... a discarded statement is not instantiated.

    This is a bit vague to me, but I conclude that it means that templates occurring in the discarded statement will not be instantiated. Other code however must be syntactically valid. A static_assert(F), [where F is false, either literally or a constexpr value] inside a discarded if constexpr clause will thus still 'bite' when the template containing the static_assert is instantiated. Or (not required, at the mercy of the compiler) already at declaration if it's known to always be false.

    Examples: (live demo)

    #include 
    
    template< typename T>
    constexpr void some_library_foo(){
        static_assert(std::is_same::value);
    }
    
    template< typename T>
    constexpr void other_library_bar(){
        static_assert(std::is_same::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::value);
        static_assert(false); // does fire already at declaration
                              // with latest version of clang
    }
    
    template
    void g() {
      if constexpr (IntCase){
        some_library_foo();
    
        // 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();
      }      
    }
    
    int main(){
        g();
        g();
    
        //g(); // ill-formed, diagnostic required
        //g(); // ill-formed, diagnostic required
    }
    

    The standard text on static_assert is remarkably short. In standardese, it's a way to make the program ill-formed with diagnostic (as @immibis also pointed out):

    7.6 ... If the value of the expression when so converted is true, the declaration has no effect. Otherwise, the program is ill-formed, and the resulting diagnostic message (1.4) shall include the text of the string-literal, if one is supplied ...

提交回复
热议问题