constexpr-if with std::is_copy_assignable

47 Views Asked by At

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

2

There are 2 best solutions below

0
Vlad from Moscow On BEST ANSWER

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.

0
kjpus On

Because

Outside a template, a discarded statement is fully checked.

(from cppreference), i.e. both if and else branches must compile, regardless of the condition.