Search code examples
c++templatesc++17type-traitsif-constexpr

constexpr-if with std::is_copy_assignable


Why does the following code not compile? The static assertion checks that Foo is not copy assignable, so I would expect that the compiler discards the code in the constexpr-if block, but it doesn't.

#include <type_traits>

struct Foo {
    Foo() = default;
    Foo const& operator=(Foo const&) = delete;
};


int main()
{
    static_assert(!std::is_copy_assignable_v<Foo>);

    Foo x;
    Foo other;
    if constexpr (std::is_copy_assignable_v<Foo>) {
        other = x;
    }
    return 0;
}

Compiler error:

<source>: In function 'int main()':
<source>:16:17: error: use of deleted function 'const Foo& Foo::operator=(const Foo&)'
   16 |         other = x;
      |                 ^
<source>:5:16: note: declared here
    5 |     Foo const& operator=(Foo const&) = delete;
      |                ^~~~~~~~
Compiler returned: 1

https://godbolt.org/z/nxf4dEhWP


Solution

  • This code snippet

    Foo x;
    Foo other;
    if constexpr (std::is_copy_assignable_v<Foo>) {
        other = x;
    }
    

    is pesent in a non-template function. So the compiler checks the validaty of the code.

    On the other hand, if you have a template code then the code that represents a substatement of the if constexpr statement will not be instantiated if the value of the expression of the if statement is evaluated to false.

    Here is a demonstration program.

    #include <iostream>
    #include <type_traits>
    
    struct Foo
    {
        Foo() = default;
        Foo const &operator=( Foo const & ) = delete;
    };
    
    template <typename T>
    void f( T &t )
    {
        if constexpr (std::is_copy_assignable_v<T>)
        {
            T t2;
            t2 = t;
        }
        else
        {
            std::cout << "I'm not copy assignable.\n";
        }
    }
    
    int main()
    {
        Foo foo;
    
        f( foo );
    }
    

    The program output is

    I'm not copy assignable.
    

    From the C++20 Standard (8.5.1 The if statement):

    2 If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool (7.7); this form is called a constexpr if statement. If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity (13.1), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.