I'm trying to write a class with multiple static constexpr values of itself; this doesn't seem to be allowed because the constexpr declaration needs the definition of the class which isn't available inside the class declaration. MCV of my first attempt looked like this:
struct A {
constexpr A(float x) : _x(x) {}
float _x;
static constexpr A y = A(1.f);
// gcc-5.1:
// error: invalid use of incomplete type 'struct A'
// static constexpr A y = A(1.f);
// ^
// msvc-14:
// error C2027: use of undefined type 'A'
// note: see declaration of 'A'
// note: see declaration of 'A'
// error C2079: 'public: static A const A::y' uses undefined struct 'A'
};
My next attempt was to declare a 'constant' class (with implicit conversion to the data class, not shown here). This seems to work fine:
struct B_constant {
constexpr B_constant(float x) : _x(x) {}
float _x;
};
struct B {
static constexpr B_constant y = B_constant(1.f);
};
But it's a little ugly, so I thought I'd try making the constant class a nested class of the data class, but this does not work:
struct C {
struct C_constant {
constexpr C_constant(float x) : _x(x) {}
float _x;
};
static constexpr C_constant y = C_constant(1.f);
// gcc-5.1:
// error: 'constexpr C::C_constant::C_constant(float)' called in a constant expression
// static constexpr C_constant y = C_constant(1.f);
// ^
// msvc-14:
// error C2131: expression did not evaluate to a constant
// note: failure was caused by call of undefined function or one not declared 'constexpr'
// note: see usage of 'C::C_constant::C_constant'
};
I noticed that the failure was similar to an error when declaring the constexpr constructor but defining it after it's used in the data class:
struct D_constant {
constexpr D_constant(float x);
float _x;
};
struct D {
static constexpr D_constant y = D_constant(1.f);
// gcc-5.1:
// error: 'constexpr D_constant::D_constant(float)' used before its definition
// static constexpr D_constant y = D_constant(1.f);
// ^
// msvc-14:
// error C2131: expression did not evaluate to a constant
// note: failure was caused by call of undefined function or one not declared 'constexpr'
// note: see usage of 'D::D_constant::D_constant'
};
constexpr D_constant::D_constant(float x) : _x(x) {}
Can anyone shed light on what's going on with the third example? It appears that the compiler cannot locate the definition of the constexpr constructor inside the nested class despite the fact that the nested class declaration is complete. Does anyone know of a better way to accomplish what I'm trying to do?
As stated here:
A class is considered a completely-defined object type (or complete type) at the closing } of the class-specifier. [...] Otherwise it is regarded as incomplete within its own class member-specification.
Where [...] is a list of exceptions that doesn't mention nested classes.
This defines member-specification:
The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere. Members of a class are data members, member functions, nested types, enumerators, and member templates and specializations thereof. [...]
Therefore, nested classes are considered part of the class specification and cannot be referred until you have a complete type (that is at the closing }, set aside the mentioned exceptions).
Data members are also part of the member specification and at the point of declaration of such a member the class must be considered as incomplete.
Note that by using the name C_constant you are actually using the qualified name C::C_constant, that is part of the definition of C. The fact that you can refer to it with a shorter identifier from within C does not alter its nature.
Does anyone know of a better way to accomplish what I'm trying to do?
It may well not be vital to you that A::y is an object rather than a function or functor.
If not then, you might work around the obstacle like:
struct A {
constexpr A(float x) : _x(x) {}
float _x;
static constexpr A y() {
return A(1.f);
}
};
constexpr A y = A::y();
static_assert(y._x == 1.f,"");
Related
This works: (A)
class Foo {
public:
const bool b;
constexpr ~Foo() = default;
constexpr Foo(const bool b) : b(b) {};
};
class Bar {
public:
static constexpr Foo tru { true };//Foo is complete type
};
This fails to compile: (B)
class Bar {
public:
class Foo {
public:
const bool b;
constexpr ~Foo() = default;
constexpr Foo(const bool b) : b(b) {};
};
static constexpr Foo tru { true };//undefined constructor 'Foo' cannot be used
};
error:
$ clang++ --std=c++20 -D_POSIX_C_SOURCE=200112L -fPIC -g -Werror -Wall LiteralStruct.cpp -o LiteralStruct
LiteralStruct.cpp:9:24: error: constexpr variable 'tru' must be initialized by a constant expression
static constexpr Foo tru { true };
^~~~~~~~~~~~
LiteralStruct.cpp:9:24: note: undefined constructor 'Foo' cannot be used in a constant expression
LiteralStruct.cpp:7:15: note: declared here
constexpr Foo(const bool b) : b(b) {};
^
1 error generated.
This also fails to compile, but gives a good reason: (C)
class Foo {
public:
const bool b;
constexpr ~Foo() = default;
constexpr Foo(const bool b) : b(b) {};
static constexpr Foo tru { true };//Foo is NOT a complete type
};
error:
$ clang++ --std=c++20 -D_POSIX_C_SOURCE=200112L -fPIC -g -Werror -Wall LiteralStruct.cpp -o LiteralStruct
LiteralStruct.cpp:6:24: error: constexpr variable cannot have non-literal type 'const Foo'
static constexpr Foo tru { true };
^
LiteralStruct.cpp:6:24: note: incomplete type 'const Foo' is not a literal type
LiteralStruct.cpp:1:7: note: definition of 'Foo' is not complete until the closing '}'
class Foo {
version:
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
C failing makes sense and has a good error message. B feels like it should work, Foo and all it's contents should be complete and defined at that point in the file. Basically my question is: do I report a clang bug that B should work, or a feature request for a better error message? If Foo is truly not complete by virtue of being a member of an incomplete type, then I should think the error message should be similar to that of C.
Edit:
I just upgraded clang to the bleeding edge (16.0.0-++20221021052626+7dd2f4bc009d-1~exp1~20221021172738.418) and got the same result.
The problem with (B) is distinct from the one with (C). In (B) the completeness of Foo is not in question. Foo is complete as soon as the closing } of its definition is reached and since the member declaration of tru is placed after that, Foo is complete for its purpose.
There is also no problem in (B) with Bar being incomplete at the declaration of tru. While that's true, incompleteness does not prevent looking up members which were declared prior, like the nested class Foo.
The problem is, as the error message is pointing out, whether or not the constructor Foo::Foo(bool) is defined at the point of the declaration of tru. This is an important question, because tru is initialized in that declaration using the constructor in question and it is marked constexpr, requiring that the initialization be a constant expression. Calling a (constexpr) function in a constant expression is only allowed if the function is defined (not only declared) prior to the expression.
Consider for example
class Bar {
public:
class Foo {
public:
const bool b;
constexpr ~Foo() = default;
constexpr Foo(const bool b);
};
static constexpr Foo tru { true };
};
constexpr Bar::Foo::Foo(const bool b) : b(b) {};
You will get the same or a similar error message here. In this case it is more obvious what the issue is. When static constexpr Foo tru { true }; is reached and the compiler tries to evaluate the (compile-time constant) value of Foo, it hasn't seen the definition of the constructor yet, so it can't know how to determine the value of tru.
Now in your example (B) it seems that Bar::Foo::Foo(bool) is defined before it is used in the constant expression for tru and I think if one follows the current standard by exact wording, then this is true. However, there is a complication which changes this in practice and in the probable intent of the standard:
The body of a function defined inside a class is special in that it is a so-called complete-class context. In such a context it is possible for name lookup to find not only preceding declarations as is normally the case in C++, but also declarations for all members of the class (and enclosing classes), irregardless of whether they are declared only later.
So for example the following is allowed:
class Bar {
public:
class Foo {
public:
const bool b;
~Foo() = default;
Foo(const bool b) : b(X) {};
};
constexpr static bool X = false;
};
Although X is not declared yet when Foo::Foo(bool) is defined and uses X, the compiler has to accept it and figure out that X is the static member declared at the end.
In order to achieve this lookup behavior, the compiler practically must rewrite the code to
class Bar {
public:
class Foo {
public:
const bool b;
~Foo() = default;
Foo(const bool b);
};
constexpr static bool X = false;
};
inline Bar::Foo(const bool b) : b(X) {};
Now "normal" lookup rules can find X as expected.
But if we apply this rewriting to your example (B) we get my first example in this answer and as we determined it cannot work with the constant expression evaluation. So in practice you can't use a member function of the same class (including nested or enclosing classes) in a constant expression evaluation for a static data member inside the class definition itself.
That the current standard wording doesn't describe this behavior properly is an issue with the standard, not the compiler. My impression is that Clang is implementing it as intended. While it may sometimes be possible to consider the constructor defined where it is lexically placed for the purpose of constant expression evaluation if e.g. all names used in its definition can already be found at that point, in general it is impossible, because you could create infinite recursive type dependencies this way.
The first thing to note is that a complete-class context of a nested class is also a complete-class context of any enclosing class, if the nested class is defined within the member-specification of the enclosing class as per mem.general#7.
This combined with the fact that the body of the constructor Bar::Foo::Foo(const bool) is a complete-class context means that the names appearing inside the body of Bar::Foo::Foo(const bool) will be lookup up as if the definition of that ctor is placed after the enclosing class' }.
This in turn implies that at the point where you have the definition/declaration of the constexpr data member tru, the constructor Bar::Foo::Foo(const bool) is not yet defined. But this violates expr.const#5 which states:
5. An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
5.2 an invocation of an undefined constexpr function;
(emphasis mine)
This is exactly what the error of one of the compiler says says:
error: constexpr variable 'tru' must be initialized by a constant expression
When I have a class with a static const or constexpr data member, defining that variable reqires me to repeat stuff:
/// my_class.hpp
class my_class { constexpr static int x = 1; };
/// my_class.cpp
#include "my_class.hpp"
// auto my_class::x; // error: declaration of 'auto my_class::x' has no initializer
// decltype(auto) my_class::x; // error: declaration of 'decltype(auto) my_class::x' has no initializer
decltype(my_class::x) my_class::x; // ok
Of course I could do
#define DEFINE_STATIC_DATA_MEMBER(x) decltype(x) x
DEFINE_STATIC_DATA_MEMBER(my_class::x);
but I wonder if there’s a non-macro solution.
The question arose because both the type and the fully-qualified name of the static data member are lengthy and I’m likely to get more of these.
Starting from C++17 you don't need to separately define static constexpr variables.
Just class my_class { constexpr static int x = 1; }; is enough, without a .cpp file.
You can make use of a typedef to not have to repeat the type when defining it.
my_class.hpp
class my_class
{
// Declaration
static const my_very_lengthy_type_name_I_dont_want_to_repeat x;
// typedef
using t = decltype(x);
};
my_class.cpp
#include "my_class.hpp"
// Initialization
my_class::t my_class::x = {};
defining that variable requires me to repeat stuff:
For static constexpr data member, the above statement is true only for Pre-C++17 standard.
From C++17 onwards, we're allowed to omit writing an out-of-class definition of a static constexpr data member. This is illustrated in the example given below.
C++11
class Foo
{
public:
static constexpr int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DECLARATION IN C++11 and C++14
//other members here
};
In the above code snippet(which is for C++11,C++14), we have a declaration of the static data member OUT_OF_BOUNDS_VALUE inside the class. And so, in exactly one translation unit we have to provide a corresponding definition. Otherwise you'll get a linker error which can be seen here.
That is, in exactly one translation unit we should write:
constexpr int Foo::OUT_OF_BOUNDS_VALUE; //note no initializer
After adding the above out of class definition with no initializer the program will work. Demo
C++17
But the out-of-class definition for static constexpr is no longer needed from C++17 onwards.
class Foo
{
public:
static constexpr int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DEFINITION IN C++17
//other members here
};
In the above code snippet(which is for C++17) we have a definition of the static data member OUT_OF_BOUNDS_VALUE inside the class. So since C++17, we don't have to provide the definition of OUT_OF_BOUNDS_VALUE anywhere else since we already have a definition for it inside the class and thus the same program works without any linker error.
So inside header files I can do
namespace X {
doThis();
}
and in the implementation file I can do
namespace X {
doThis() { .... }
}
But if I have a class
class X {
public:
doThis();
};
Is it possible for me to do something like this in the implementation file
class X {
doThis() { .... }
}
instead of X::doThis() { .... }?
There's the "Java hack"¹, where you "inherit" from the class to get its members into your namespace:
class MyUserType : /*protected|private*/ X {
void foo() {
doThis(); // works
}
}
Of course this only works of
the class doesn't define additional (non-static) features that interfere when inherited
your calling code is in a class that can inherit from the type
the derived class is not a template because 2-phase lookup makes things weird again (though you can use using declarations to mitigate them, on a name-by-name basis)
Re: static data members/out of class definition
In the comments you seem to have a problem with brevity of code mostly. Look into
Disclaimer: following examples largely copied from cppreference
inline variables (c++17), which is about namespace level static variables, which also applies to class members:
constexpr/const static member initialization right in the declaration.
If a static data member of integral or enumeration type is declared const (and not volatile), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
struct X
{
const static int n = 1;
const static int m{2}; // since C++11
const static int k;
};
const int X::k = 3;
constexpr members are even required to have the initializer in the declaration:
struct X {
constexpr static int arr[] = { 1, 2, 3 }; // OK
constexpr static std::complex<double> n = {1,2}; // OK
constexpr static int k; // Error: constexpr static requires an initializer
};
Note that in some circumstances you may still need out-of-class definitions, but without the initializer:
If a const non-inline (since C++17) static data member or a constexpr static data member (since C++11)(until C++17²) is odr-used, a definition at namespace scope is still required, but it cannot have an initializer. A definition may be provided even though redundant (since C++17).
struct X {
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n; // … so a definition is necessary
constexpr int X::m; // … (except for X::m in C++17)
¹ for the longest time Java didn't have enumerations, so you'd define static constants in a base class an "inherit" from it to get the constants.
² If a static data member is declared constexpr, it is implicitly inline and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated.
I have a template base class, whereby subclasses are expected to pass themselves as the template parameter.
It looks a little like this:
template<typename T>
struct Base {
constexpr Base(int x) : m_x(x) {}
private:
int m_x;
};
struct Derived : public Base<Derived>
{
static const Derived LIFE;
constexpr Derived(int x) : Base(x) {}
};
const Derived Derived::LIFE = Derived(42);
That compiles and works as expected. But now I'd like to make Derived::LIFE a constexpr. Is this even possible?
I can't just change it's const qualifier to constexpr, as a constexpr needs to be initialized in its declaration:
test.cpp:10:28: error: constexpr static data member ‘LIFE’ must have an initializer
static constexpr Derived LIFE;
I can't initialize it there since Derived is an incomplete type:
test.cpp:10:45: error: invalid use of incomplete type ‘struct Derived’
static constexpr Derived LIFE = Derived(42);
I realize this problem would go away if Derived were a complete type, but I'm pretty attached to the self-referential templated base class in this particular case for reasons not relevant to this question.
If I understand the last paragraph in this answer correctly, it sounds like there is at least some discussion about changing the way incomplete types are handled at some point in the future, but that doesn't help me now.
Is anyone aware of some sort of trick to defer the initialization of LIFE in my above code?
You can simply add constexpr to the definition of LIFE:
constexpr Derived Derived::LIFE = Derived(42);
Until recently GCC had a bug where it rejected this; you'll need to use either Clang or GCC 4.9.
I think you shall use lazy initialization. Actually Derived is still incomplete type; because the compiler don't know its size yet.
So the code shall be:
struct Derived : public Base<Derived>
{
constexpr Derived(int x) : Base(x) {}
static constexpr Derived getLIFE()
{
return Derived(34);
}
};
EDIT:
Same incomplete type behavior can be reproduced using this snippet:
struct MyStruct
{
static constexpr int x = sizeof(MyStruct);
};
Please consider the following mini example
// CFoo.hpp
class CFoo{
private:
static const double VPI = 0.5;
public:
double getVpi();
};
// CFoo.cpp
#include "CFoo.hpp"
double CFoo::getVpi(){
double x = -VPI;
return x;
}
// main.cpp
#include "CFoo.hpp"
int main(){
CFoo aFoo();
return 0;
}
Lining the program with gcc version 4.5.1 produces the error CFoo.cpp: undefined reference to CFoo::VPI. The error dose not occur if
VPI is not negated
the negation is written as double x = -1 * VPI;
Declaration and definition of class CFoo happen in the same file
Do you know the reason for this error?
There are multiple problems with your code. Primarily, this is not valid C++03:
class CFoo{
private:
static const double VPI = 0.5;
// ...
};
The declaration of a static data member can specify a constant initializer if and only if that initializer is const integral or const enumeration type. 0.5 is neither of these, and hence your code is not valid C++. 9.4.2 Static data members covers this:
2/ The declaration of a static data member in its class definition is
not a definition [...]The definition for a static data member shall
appear in a namespace scope enclosing the member’s class definition.
[...]
4/ If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constant-initializer which shall be an integral constant expression
(5.19).
In order to initialize VPI, you must do so in the CPP file:
header:
class CFoo{
private:
static const double VPI;
};
cpp :
const double CFoo::VPI = 0.5;
Another problem, unrelated, is here:
int main(){
CFoo aFoo(); // NOT OK
return 0;
The expression CFoo aFoo(); doesn't do what you think it does. You think it declares an object aFoo of type CFoo and initializes it using CFoo's default constructor. But what it actually does is declare a function named aFoo taking no parameters, returning a CFoo by value. This is known as the most vexing parse. In order to do what you want, simple omit the parenthesis:
CFoo aFoo;