0

Probably easiest to explain if I show an example:

#include <iostream>
#include <type_traits>

class Unconstructible
{
public:
    Unconstructible() = delete;
};


int main()
{
    if constexpr (std::is_constructible_v<Unconstructible>)
    {
        std::cout << "Unconstructible is constructible. What?\n";
        // Unconstructible foo;
    }
    else
    {
        std::cout << "Unconstructible is not constructible.\n";
    }

    return 0;
}

This outputs "Unconstructible is not constructible" as expected. If, however, I uncomment the line Unconstructible foo;, I get a compilation error:

1>F:\Programming\C++\CppScratchwork\CppScratchwork\CppScratchwork\CppScratchwork.cpp(48): error C2280: 'Unconstructible::Unconstructible(void)': attempting to reference a deleted function
1>F:\Programming\C++\CppScratchwork\CppScratchwork\CppScratchwork\CppScratchwork.cpp(39): message : see declaration of 'Unconstructible::Unconstructible'
1>F:\Programming\C++\CppScratchwork\CppScratchwork\CppScratchwork\CppScratchwork.cpp(39,5): message : 'Unconstructible::Unconstructible(void)': function was explicitly deleted
1>Done building project "CppScratchwork.vcxproj" -- FAILED.

That's in MSVC using /std:c++17. The same behavior shows up on GCC with -std=c++17 but with differently-worded error messages involving attempting to reference a deleted function.

Why is it even attempting to compile the first part of the if constexpr branch? As far as I can tell, it is correctly able to tell that std::is_constructible_v<Unconstructible> is false.

Nathan Pierson
  • 5,461
  • 1
  • 12
  • 30
  • 2
    To summarize the duplicate (there may be a better one): *This means every branch in an if constexpr block must be valid C++, even if it's never going to be used.* – Adrian Mole Apr 06 '21 at 15:41
  • Too bad the duplicate doesn't define "valid C++" very well. Apparently more is needed than merely to be parseable. – Thomas Apr 06 '21 at 15:44
  • Ah. I think the misunderstanding I had was for the fact that the un-taken branch of `if constexpr` doesn't attempt to instantiate templates that would only be instantiated there and over-generalized that to "code in un-taken branches of `if constexpr` doesn't really have to compile". – Nathan Pierson Apr 06 '21 at 15:45
  • Added a second duplicate target that emphasizes the difference when using templates; in that case, you *can* have 'badly-formed' code (sort of). – Adrian Mole Apr 06 '21 at 15:49
  • That explains why, for instance, I can happily put `auto p_unconstructible = std::make_unique();` in the upper branch, because that's only invalid if it actually attempts to instantiate the template function. – Nathan Pierson Apr 06 '21 at 15:52

0 Answers0