Constexpr class: Inheritance?

我怕爱的太早我们不能终老 提交于 2019-12-13 14:43:24

问题


First of all, I'm working with Clang 3.4.1

I'm writting a global variable which has to serve as a placeholder on compile-time contexts (Primarily as value template parameter). For that purpose, I have written a constexpr class named chameleon (It mimics the behaviour of any runtime value):

struct chameleon
{
    template<typename T>
    constexpr operator T() const
    {
        return T{};
    }

    constexpr chameleon() = default;
};

Since both the conversion operator and the constructor are specified as constexpr, I'm able to make instances of that class at compile-time. For example:

template<int foo>
struct bar
{};

using mytype = bar<chameleon{}>;

Since this works, and I use it in other places, I decided to write such placeholder type just inheriting from chameleon:

template<std::size_t I>
struct placeholder : public chameleon
{
    using chameleon::chameleon;
};

I'm using C++11, so I just used the "new" (C++11 has three years...) inheriting constructors feature.

When declaring the placeholder variable:

constexpr const placeholder<0> _1;

The compiler rejects the code saying it expects an user-defined default ctor for initialization. So "Well, inheriting ctors doesn't propagate constexpr, or something like that" is what I though. Then I changed the using to a default ctor declaration:

template<std::size_t I>
struct placeholder : public chameleon
{
    constexpr placeholder() = default;
};

Now the compiler says:

error: default initialization of an object of const type 'const placeholder<0>' requires a user-provided default constructor

If I change the = default to a manually defined empty constructor (constexpr placeholder() {}) then it works, but the constructor is not evaluated as constexpr and the usage of the _ placeholder in compile-time contexts is invalid (The common is not a constant expression error). The same for manually calling the base ctor.

My question is: Whats wrong with inheritance and constexprconstructors? Is there any way to use inheritance when writting constexpr classes?

EDIT: I have a division-by-zero bug, the code using the manually written ctor works perfectly. On the other hand, I don't understand why neither the inheriting constructor or the default constructor declaration worked. The question remains there.


回答1:


So "Well, inheriting ctors doesn't propagate constexpr, or something like that" is what I thought

That's not the issue; default and copy/move constructors cannot be inherited. If you don't explicitly define or default them, they'll be implicitly defined following the usual rules.

§12.9 [class.inhctor]

3      For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class. ...

5      [ Note: Default and copy/move constructors may be implicitly declared as specified in 12.1 and 12.8. —end note ]

Consequently, placeholder, with or without the using declaration for inheriting chameleon's constructors, will have a default constructor implicitly defined, and this constructor will be constexpr.

§12.1/5 [class.ctor]

... If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr. ...

Your class, with a user provided default constructor, satisfies the requirements in §7.1.5/4 for a constexpr constructor. The error you saw was because of the next part.


As for why you must provide a constructor definition for a const object, let's take a look at your class.

struct chameleon
{
    template<typename T>
    constexpr operator T() const
    {
        return T{};
    }

    constexpr chameleon() = default;
};

This class is both trivial (9/6) and standard layout (9/7), hence it is a POD (9/10). A POD is uninitialized by default, so a const POD without an initializer would be uninitialized, and immutable, making it pretty much worthless (or I'm not able to think of any use cases, at least).

By providing a default constructor, the class is no longer a POD, and will be default initialized.

As @Casey points out in the comments, this requirement is listed in §8.5/7

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.



来源:https://stackoverflow.com/questions/24333458/constexpr-class-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!