问题
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 constexpr
constructors? 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 isconstexpr
. ...
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