I'm having trouble with the following code:
template<typename T>
constexpr int get(T vec) {
return vec.get();
}
struct coord {
constexpr int get() const { return x; }
int x;
};
struct foo {
struct coord2 {
constexpr int get() const { return x; }
int x;
};
constexpr static coord f = { 5 };
constexpr static int g = get(f); // works
constexpr static coord2 h = { 5 };
constexpr static int i = get(h); // doesn't work
};
constexpr coord foo::f;
constexpr foo::coord2 foo::h;
int main(){}
Essentially, get(f) is considered a constant expression, but get(h) is not. The only thing changed is that one uses a global struct coord, while the other uses a nested struct coord2. The structs'
bodies are identical.
Why is this?
GCC error:
test.cpp:20:35: error: field initializer is not constant
Clang error:
test.cpp:20:26: error: constexpr variable 'i' must be initialized by a constant expression
constexpr static int i = get(h); // doesn't work
^ ~~~~~~
test.cpp:8:10: note: undefined function 'get' cannot be used in a constant expression
return vec.get();
^
test.cpp:20:30: note: in call to 'get({5})'
constexpr static int i = get(h); // doesn't work
^
test.cpp:13:21: note: declared here
constexpr int get() const { return x; }
It is a constant expression.... eventually, as this shows you can see by moving i into main():
http://ideone.com/lucfUi
The error messages are pretty clear what's going on, which is that foo::coord2::get() isn't defined yet, because member function definitions are delayed until the end of the enclosing class so that they can use members declared later.
It's a little surprising that the definition is delayed until the end of the outermost enclosing class, but you'd be even more surprised if foo::coord2::get() couldn't access foo::g.
The Standard agrees with the compiler, btw. Part of section 9.2p2 says
Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes).
Unfortunately, it's only inferred that the closing brace of the class declaration becomes the point-of-definition for these deferred regions. I believe it's a defect in the Standard that it doesn't say this explicitly.
See also:
https://stackoverflow.com/a/11523155/103167
Related
I have a class for local use only (i.e., its cope is only the c++ file it is defined in)
class A {
public:
static const int MY_CONST = 5;
};
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error:
// undefined reference to `A::MY_CONST`
}
All the code reside in the same c++ file. When compiling using VS on windows, there is no problem at all.
However, when compiling on Linux I get the undefined reference error only for the second statement.
Any suggestions?
std::min<int>'s arguments are both const int&(not just int), i.e. references to int. And you can't pass a reference to A::MY_CONST because it is not defined (only declared).
Provide a definition in the .cpp file, outside the class:
class A {
public:
static const int MY_CONST = 5; // declaration
};
const int A::MY_CONST; // definition (no value needed)
// initialize static constants outside the class
class A {
public:
static const int MY_CONST;
};
const int A::MY_CONST = 5;
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error:
// undefined reference to `A::MY_CONST`
}
To explain what's happening here:
You declared static const integer inside class, this "feature" is here to be able to use it as constant expression,i.e. for local array size, template non-type parameters, etc.. If compiler wants to use this constant expression it must be able to see it's value in that translation unit.
9.5/3
If a non-volatile const static data member is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment expression is a constant expression (5.19). A static data member of literal type can be declared in the
class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer
in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both
these cases, the member may appear in constant expressions. — end note ] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.
odr-used means to form reference to that variable or take it's address.
std::min takes it's parameters by reference, so they are odr-used.
Solution:
Define it!
class A
{
static const int a = 5;
};
const int A::a; //definition, shall not contain initializer
You can also save the const value to a local variable.
class A {
public:
static const int MY_CONST = 5;
};
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error: undefined reference to `A::MY_CONST`
int l = std::min<int>( j, b); // works
}
I am having a very strange situation
template<class T> class Strange {
public:
static const char gapchar='-';
};
template<class T> void Strange<T> method1 {
char tmp = gapchar;
}
template<class T> void Strange<T> method2 {
char tmp = gapchar;
}
I include the above class, it has been working for several years.
I added another method, essentially the same signature and just reading the gapchar.
I got undefined error only for the third method, even I am using all three methods.
Then I changed the way I initialize the static variable by
not initializing in the class definition:
static const char gapchar;
template<class T> const char Strange<T>::gapchar='-';
This solved the problem. I could not figure out why the old way of
initializing int or char type (the only two types allowed) inside the class
definition section stop working for only one of the methods but not others.
If you are using some header-only thing and want to avoid having to add a .cpp file, it seems like you can do this:
class A {
public:
static inline const int MY_CONST = 5;
};
(or `static inline constexpr`)
This requires C++17
I'm running into an error when trying to access a constexpr member variable of a derived class through a base class reference via CRTP;
template <typename Der>
struct Base
{
constexpr std::size_t getsize()
{
constexpr const auto &b = static_cast<Der*>(this)->arr;
return b.size();
//return static_cast<Der*>(this)->arr.size(); // this works
}
};
struct Derived : Base<Derived>
{
static constexpr std::array<int, 10> arr = {};
};
int main(){
Derived d;
return d.getsize();
}
Error:
<source>:11:31: error: constexpr variable 'b' must be initialized by a constant expression
constexpr const auto &b = static_cast<Der*>(this)->arr;
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:24:14: note: in instantiation of member function 'Base<Derived>::getsize' requested here
return d.getsize();
^
<source>:11:53: note: use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function
constexpr const auto &b = static_cast<Der*>(this)->arr;
^
1 error generated.
Compiler returned: 1
Update
It turns out that removing the constexpr in the reference works. I'd like to understand why this works ?
auto &b = static_cast<Der*>(this)->arr;
return b.size();
Informally, you should imagine there being a rule that a constexpr variable defined inside a function is required to be initialized by an expression that is always a constant expression regardless of the circumstances under which the function is called. In particular, you can always do something like this:
Base<Derived> b;
b.getSize();
in which case static_cast<Der*>(this)->arr is not a constant expression, since it is in fact UB. Because of the possibility of things like this, your function can't compile at all even though you may never call it in this manner anyway.
The actual rule you are violating is [expr.const]/5.1. A constant expression E may not evaluate this, unless it's by (directly or indirectly) calling some member function inside of which the evaluation of this occurs. In particular, this means that if we have some code like this:
// namespace scope
struct S {
constexpr const S* get_self() {
const S* result = this;
return result;
}
};
constexpr S s;
constexpr const S* sp = s.get_self();
Here, s.get_self() is a constant expression, because the access to this only occurs inside the get_self() function, which is part of the evaluation of s.get_self(). But we cannot make result constexpr, because if it were so, we no longer get to "count" the enclosing function; the initialization step would have to qualify in and of itself as a constant expression, which it is not, since the access to this is now "bare".
For your code this implies that getsize() actually may return a constant expression (for those calls that do not trigger UB as described above) but b cannot be made constexpr.
I am using g++4.8.0, which doesn't contain earlier constexpr bug. Thus below code works fine:
constexpr int size() { return 5; }
int array[size()];
int main () {}
However, if I enclose both the variable inside a class as static, then it gives compiler error:
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
int main () {}
Here is the error:
error: size of array ‘array’ is not an integral constant-expression
Is it forbidden to use constexpr in such a way or yet another g++ bug?
Yes, it is ill-formed. Here's why:
A constexpr function needs to be defined (not just declared) before being used in a constant expression.
So for example:
constexpr int f(); // declare f
constexpr int x = f(); // use f - ILLEGAL, f not defined
constexpr int f() { return 5; } // define f, too late
function definitions inside a class specifier (as well as initializers and default parameters) are essentially parsed in an order like they were defined outside the class.
So this:
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
Is parsed in this order:
struct X {
constexpr inline static int size(); // function body defered
static const int array[size()]; // <--- POINT A
};
constexpr inline int X::size() { return 5; }
That is, parsing of function bodies are defered until after the class specifier.
The purpose of this deferral of function body parsing is so that function bodies can forward reference class members not yet declared at that point, and also so they can use their own class as a complete type:
struct X
{
void f() { T t; /* OK */ }
typedef int T;
};
Compared to at namespace scope:
void f() { T t; /* error, T not declared */ }
typedef int T;
At POINT A, the compiler doesn't have the definition of size() yet, so it can't call it. For compile-time performance constexpr functions need to be defined ahead of their use in the translation unit before being called during compile, otherwise the compiler would have to make a multiple passes just to "link" constant expressions for evaluation.
Apparently it's not even a bug, because its status is RESOLVED INVALID, which means that the people behind GCC and that bugzilla, after reviewing the problem, don't think that this is a GCC bug.
I remind you on that page because there is also an answer for this behaviour in one of the related posts.
I just wanted to add that even though this may not be good practice and will restrict you to defining the class body in the same compilation unit that its declared, it's possible to force the compiler to compile the definition of the function bodies at the same point as its declaration by adding a redundant template parameter:
template <typename = void>
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
int main()
{
X<> x{};
...
}
I want to define an aggregate with a number of mutable fields (to save it in std::set or std::priority_queue and modify it in future, surely saving the container invariants). I tried the following syntax and it was compiled successfully:
#include <cstdlib>
int
main()
{
struct X
{
mutable struct
{
int i;
int j;
};
};
X const x{};
//x.i = 1;
return EXIT_SUCCESS;
}
Live example for clang 3.8.
But statement x.i = 1; gives an error:
error: cannot assign to variable 'x' with const-qualified type 'const X'
My intention was to group a plenty of sequential fileds and apply mutable keyword to the group.
Is this syntax wrong? If so, what is an intention of compiler makers to allow such a syntax if any?
ADDITIONAL:
Code:
#include <cstdlib>
int
main()
{
struct X
{
mutable struct
{
int i;
int j;
};
void f() const { i = 1; }
};
X const x{};
//x.i = 1;
x.f();
return EXIT_SUCCESS;
}
gives an error too:
error: cannot assign to non-static data member within const member function 'f'
note: member function 'main()::X::f' is declared const here
void f() const { i = 1; }
The trouble comes from the mix between the non-standard (in C++) usage of anonymous struct together with the mutable. The latter is a storage class specifier that is meant to be used for members and not for types.
Alternative 1: define an intermediate member for your anonymous struct:
You can define a member that will then be mutable, according to the rules of standard C++:
struct X
{
mutable struct
{
int i;
int j;
} y;
};
X const x{};
x.y.i = 1;
Live demo
Alternative 2: make every members in the anonymous struct mutable:
You can otherwise define the members within the struct as being mutable. As the anonymous struct merges these members into the enclosing struct, the mutable property will be passed on:
struct X
{
struct
{
mutable int i;
mutable int j;
};
};
Online demo
What does the standard say ?
The standatad C++ doen't allow anonymous struct. Anonymous struct is a compiler extension for C11 compatibility.
The C++ standard allows however anonymous unions. But it sets restrictions, notably:
9.5/6: A storage class is not allowed in a declaration of an anonymous union in a class scope.
So when compiling the following code:
struct X
{
mutable union
{
int i;
int j;
};
};
the compiler shall and will issue a very specific error:
prog.cpp:11:13: error: a storage class on an anonymous aggregate in class scope is not allowed
mutable union
I think that it is not consistent to allow using a storage class specifier on an anonymous struct (and apparently ignoring it) and to issues an error for an anonymous union. According to me, this shall be reported as a compiler bug. In anycase, you should adopt alternative 1 (portable & compliant) or alternative 2 (compiler dependent, but more consistent with the standard).
I have a class for local use only (i.e., its cope is only the c++ file it is defined in)
class A {
public:
static const int MY_CONST = 5;
};
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error:
// undefined reference to `A::MY_CONST`
}
All the code reside in the same c++ file. When compiling using VS on windows, there is no problem at all.
However, when compiling on Linux I get the undefined reference error only for the second statement.
Any suggestions?
std::min<int>'s arguments are both const int&(not just int), i.e. references to int. And you can't pass a reference to A::MY_CONST because it is not defined (only declared).
Provide a definition in the .cpp file, outside the class:
class A {
public:
static const int MY_CONST = 5; // declaration
};
const int A::MY_CONST; // definition (no value needed)
// initialize static constants outside the class
class A {
public:
static const int MY_CONST;
};
const int A::MY_CONST = 5;
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error:
// undefined reference to `A::MY_CONST`
}
To explain what's happening here:
You declared static const integer inside class, this "feature" is here to be able to use it as constant expression,i.e. for local array size, template non-type parameters, etc.. If compiler wants to use this constant expression it must be able to see it's value in that translation unit.
9.5/3
If a non-volatile const static data member is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment expression is a constant expression (5.19). A static data member of literal type can be declared in the
class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer
in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both
these cases, the member may appear in constant expressions. — end note ] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.
odr-used means to form reference to that variable or take it's address.
std::min takes it's parameters by reference, so they are odr-used.
Solution:
Define it!
class A
{
static const int a = 5;
};
const int A::a; //definition, shall not contain initializer
You can also save the const value to a local variable.
class A {
public:
static const int MY_CONST = 5;
};
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error: undefined reference to `A::MY_CONST`
int l = std::min<int>( j, b); // works
}
I am having a very strange situation
template<class T> class Strange {
public:
static const char gapchar='-';
};
template<class T> void Strange<T> method1 {
char tmp = gapchar;
}
template<class T> void Strange<T> method2 {
char tmp = gapchar;
}
I include the above class, it has been working for several years.
I added another method, essentially the same signature and just reading the gapchar.
I got undefined error only for the third method, even I am using all three methods.
Then I changed the way I initialize the static variable by
not initializing in the class definition:
static const char gapchar;
template<class T> const char Strange<T>::gapchar='-';
This solved the problem. I could not figure out why the old way of
initializing int or char type (the only two types allowed) inside the class
definition section stop working for only one of the methods but not others.
If you are using some header-only thing and want to avoid having to add a .cpp file, it seems like you can do this:
class A {
public:
static inline const int MY_CONST = 5;
};
(or `static inline constexpr`)
This requires C++17