1

Why does this code only compile if I remove the = 0?

#include <type_traits>

struct Foo
{
    virtual ~Foo() noexcept = default;
    Foo() = default;
    Foo(Foo &&) noexcept = default;
    Foo(Foo const &) = default;
    Foo &operator =(Foo &&) noexcept = default;
    Foo &operator =(Foo const &) = default;
    virtual void foo() = 0;
};

static_assert(std::is_nothrow_move_constructible<Foo>::value);
user541686
  • 205,094
  • 128
  • 528
  • 886

1 Answers1

2

Short version:
A variable of abstract type cannot be constructed. Removing the = 0 makes the class no longer abstract.

Long version:
First, I would like to simplify the question since the "nothrow" part is a (potentially confusing) red herring. Thestatic_assert still fails if "nothrow" is removed, as in

static_assert(std::is_move_constructible<Foo>::value);

The definition of std::is_move_constructible<T> leads to the definition of std::is_constructible. These combine to say that std::is_move_constructible<Foo>::value is true only when a variable of type Foo can be constructed from a value of type Foo&&. Since Foo is an abstract type (with the = 0 in its definition), this construction – in fact, construction from any collection of parameter types – is not allowed. Hence the value is false and the static_assert fails.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • +1, and to clarify: this implies it's impossible to tell if an abstract class has any particular kind of constructor—correct? (In my case I was trying to detect nothrow-ness, but then ran into this.) I guess it's one difference between the old `has_XYZ_constructor` proposal and the `is_XYZ_constructible` that we actually got - just because a constructor exists that doesn't mean anyone can call it! – user541686 Aug 29 '22 at 00:14
  • @user541686 Can't you inherit from this class and test by calling that constructor from the derived class? – Sebastian Aug 29 '22 at 05:08
  • 1
    @Sebastian: I don't think know of any way to "test" (i.e. SFINAE) a constructor call from a derived class. That is, unless I define all the abstract methods first, so that the derived class isn't abstract anymore. But that doesn't work for the generic case, where the class is a template and you have no idea what the signatures of its abstract methods are. – user541686 Aug 29 '22 at 06:59