Why does emplace_back take a reference of the member that requires a definition? What is the difference between emplace_back(integer literal) and emplace_back(static constexpr integer member)?
If I switch to C++17, it compiles fine. I found that in C++17 static constexpr data members are implicitly inlined. Does it mean the compiler implicitly creates a definition for them?
Example code:
class base {
int n;
public:
base(int n):n(n) {}
};
struct base_trait {
static constexpr int n = 1;
};
int main(void) {
vector<base> v;
v.emplace_back(1); // ok
v.emplace_back(base_trait::n); // link error with -std=c++14, ok with -std=c++17
return 0;
}
As you said, emplace_back takes arguments by reference, so passing base_trait::n causes it to be odr-used.
an object is odr-used if its value is read (unless it is a compile time constant) or written, its address is taken, or a reference is bound to it;
Before C++17, that means the definiton of base_trait::n is required here. But since C++17 the behavior changed, for constexpr static data member the out-of-class definition is not needed again.
If a const non-inline (since C++17) static data member or a constexpr static data member (since C++11) is odr-used, a definition at namespace scope is still required, but it cannot have an initializer. This definition is deprecated for constexpr data members (since C++17).
A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition. (since C++17)
Related
consider a class with a constant member:
class foo {
public:
const static int N;
};
foo::N needs to initialized:
constexpr int foo::N = 5;
and note how using the constexpr qualifier instead of const here seems like a mistake.
but GCC, Clang and MSVC all compile just fine!
is there something in the language that allows changing qualifiers here?
is it an error overlooked by all three compilers?
Clang even allows both qualifier versions simultaneously:
constexpr int foo::N = 3;
const int foo::N = 5;
int main(){
return foo::N; //returns 3
}
what's going on?
Since obviously the value of a variable that has been declared but not defined cannot be used in a constant expression, constexpr pertains only to the definition of a variable. (Of course, if the variable is inline, perhaps because of being a static member declared constexpr, every definition must have constexpr.) It implies const (on the variable itself: constexpr char* is char *const, not const char*), so you haven’t changed the variable’s type. This is no different from
// foo.hpp
extern const int x;
// foo.cpp
constexpr int x=2;
which is perhaps less surprising.
So everything is fine! The variable’s value can be used in constant expressions only in the translation unit that contains the definition, but that’s no surprise, and could easily be construed as a feature for modularity. Clang is buggy to allow two definitions: presumably it’s trying to ignore the (deprecated, as of C++17) out-of-class definition for a constexpr static data member defined in the class.
Why doesn't the following minimal example compile with c++11 nor c++14, but compiles in c++17 and c++2a?
#include <iostream>
#include <limits>
#include <vector>
// works:
// static constexpr int VALUE_LIMIT_A = std::numeric_limits<int>::max();
class Classy {
// does not work in c++11 (constexpr introduced) nor c++14:
// works if c++17 or newer:
static constexpr int VALUE_LIMIT_A = std::numeric_limits<int>::max();
int VALUE_LIMIT_B = std::numeric_limits<int>::max();
public:
explicit Classy();
std::vector<int> classy;
};
Classy::Classy() {
// does not work:
classy.resize(3, VALUE_LIMIT_A);
// works:
// classy.resize(3, std::numeric_limits<int>::max());
// works:
// std::cout << VALUE_LIMIT_A;
// works:
// classy.resize(3, VALUE_LIMIT_B);
}
// required in c++11 and c++14
// constexpr int Classy::VALUE_LIMIT_A;
int main() {
Classy classy{};
for (const auto& elem : classy.classy) {
std::cout << elem << ",";
}
std::cout << "\n";
}
Here is output with c++11:
$ g++ -std=c++11 main.cpp && ./a.out
/tmp/ccon7pPo.o: In function `Classy::Classy()':
main.cpp:(.text+0x31): undefined reference to `Classy::VALUE_LIMIT_A'
collect2: error: ld returned 1 exit status
Here is output with c++17:
$ g++ -std=c++17 main.cpp && ./a.out
2147483647,2147483647,2147483647,
Because since C++17, the definition of the constexpr static data member at namespace scope is not required again.
If a const non-inline (since C++17) static data member or a constexpr static data member (since C++11) is odr-used, a definition
at namespace scope is still required, but it cannot have an
initializer. This definition is deprecated for constexpr data members (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)
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. (since C++17)
And note that std::vector::resize takes the 2nd parameter by reference; which cause VALUE_LIMIT_A to be odr-used for classy.resize(3, VALUE_LIMIT_A);.
Since C++17, with the introduction of inline variables, static constexpr data members are implicitly inline variables:
[dcl.constexpr]
1 ... A function or static data member declared with the constexpr
specifier is implicitly an inline function or variable
([dcl.inline])...
Inline variables, like inline functions, are defined in every translation units they are used in. And the compiler resolves the multiple definitions into a single one. This means, the unlike C++14, there is no need to explicitly provide an out of class definition for a static constexpr variable for the sake of the ODR, the compiler takes care of it.
You can also get away with it in C++14, too. Like the other answer mentions, it is resize that ODR-uses the static data member. You can work around it, though:
classy.resize(3, int(VALUE_LIMIT_A));
While it looks superfluous, it in fact has different behavior to using the constant directly. This creates an integer temporary, with the value of the constant. But it doesn't ODR-use the constant. The temporary is bound to the reference instead, and so the problem is avoided. While it's better to define the constant in pre-C++17 code, you can use this trick to adapt code you have no control over.
I've run into what seems a counterintuitive error, namely, the inability to assign the value of a constexpr function to a constexpr literal (hope I'm using the language right). Here's the example:
class MyClass {
public:
static constexpr int FooValue(int n) { return n + 5; }
static constexpr int Foo5 = FooValue(5); // compiler error
static constexpr int Foo5Alt(void) { return FooValue(5); } // OK
};
In GCC 4.8.4, Foo5 is flagged for field initializer is not constant. Found this thread suggesting that the older version of GCC might be the culprit. So I plugged it into Coliru (GCC 6.2.0) and got the error 'static constexpr int MyClass::FooValue(int)' called in a constant expression before its definition is complete. I added Foo5Alt() which returns its value as a constexpr function rather than literal, and that compiles fine.
I guess I'm not following why FooValue(5) can't be used as the initializer for Foo5. The definition for FooValue(int n) is complete, isn't it? { return n + 5; } is the entire definition. constexpr denotes an expression that can be fully evaluated at compile time, so why can it not be used to define the return value of a constexpr literal?
What subtlety of C++ am I missing?
In C++, inline definitions of member functions for a class are only parsed after the declaration of the class is complete.
So even though the compiler "knows" about MyClass::FooValue(int), it hasn't "seen" its definition yet, and hence it can't be used in a constexpr expression.
A general workaround for this is to stick to constexpr member functions, or declare constexpr constants outside the class.
According to the standard, MyClass is considered an incomplete type when you try to invoke FooValue to initialize Foo5. Therefore, you cannot use its members as you did.
The type is considered a completely-defined object type (or complete type) at the closing }.
On the other side, the class is regarded as complete within function bodies. That's why Foo5Alt compiles just fine.
See [class.mem]/6 for further details.
Why can't I initialize non-const static member or static array in a class?
class A
{
static const int a = 3;
static int b = 3;
static const int c[2] = { 1, 2 };
static int d[2] = { 1, 2 };
};
int main()
{
A a;
return 0;
}
the compiler issues following errors:
g++ main.cpp
main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member ‘b’
main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type ‘const int [2]’
main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type ‘int [2]’
I have two questions:
Why can't I initialize static data members in class?
Why can't I initialize static arrays in class, even the const array?
Why I can't initialize static data members in class?
The C++ standard allows only static constant integral or enumeration types to be initialized inside the class. This is the reason a is allowed to be initialized while others are not.
Reference:
C++03 9.4.2 Static data members
§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 that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.
What are integral types?
C++03 3.9.1 Fundamental types
§7
Types bool, char, wchar_t, and the signed and unsigned integer types are collectively called integral types.43) A synonym for integral type is integer type.
Footnote:
43) Therefore, enumerations (7.2) are not integral; however, enumerations can be promoted to int, unsigned int, long, or unsigned long, as specified in 4.5.
Workaround:
You could use the enum trick to initialize an array inside your class definition.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Why does the Standard does not allow this?
Bjarne explains this aptly here:
A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.
Why are only static const integral types & enums allowed In-class Initialization?
The answer is hidden in Bjarne's quote read it closely,
"C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects."
Note that only static const integers can be treated as compile time constants. The compiler knows that the integer value will not change anytime and hence it can apply its own magic and apply optimizations, the compiler simply inlines such class members i.e, they are not stored in memory anymore, As the need of being stored in memory is removed, it gives such variables the exception to rule mentioned by Bjarne.
It is noteworthy to note here that even if static const integral values can have In-Class Initialization, taking address of such variables is not allowed. One can take the address of a static member if (and only if) it has an out-of-class definition.This further validates the reasoning above.
enums are allowed this because values of an enumerated type can be used where ints are expected.see citation above
How does this change in C++11?
C++11 relaxes the restriction to certain extent.
C++11 9.4.2 Static data members
§3
If a static data member is of const literal 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. 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 used in the program and the namespace scope definition shall not contain an initializer.
Also, C++11 will allow(§12.6.2.8) a non-static data member to be initialized where it is declared(in its class). This will mean much easy user semantics.
Note that these features have not yet been implemented in latest gcc 4.7, So you might still get compilation errors.
This seems a relict from the old days of simple linkers. You can use static variables in static methods as workaround:
// header.hxx
#include <vector>
class Class {
public:
static std::vector<int> & replacement_for_initialized_static_non_const_variable() {
static std::vector<int> Static {42, 0, 1900, 1998};
return Static;
}
};
int compilation_unit_a();
and
// compilation_unit_a.cxx
#include "header.hxx"
int compilation_unit_a() {
return Class::replacement_for_initialized_static_non_const_variable()[1]++;
}
and
// main.cxx
#include "header.hxx"
#include <iostream>
int main() {
std::cout
<< compilation_unit_a()
<< Class::replacement_for_initialized_static_non_const_variable()[1]++
<< compilation_unit_a()
<< Class::replacement_for_initialized_static_non_const_variable()[1]++
<< std::endl;
}
build:
g++ -std=gnu++0x -save-temps=obj -c compilation_unit_a.cxx
g++ -std=gnu++0x -o main main.cxx compilation_unit_a.o
run:
./main
The fact that this works (consistently, even if the class definition is included in different compilation units), shows that the linker today (gcc 4.9.2) is actually smart enough.
Funny: Prints 0123 on arm and 3210 on x86.
It's because there can only be one definition of A::a that all the translation units use.
If you performed static int a = 3; in a class in a header included in all a translation units then you'd get multiple definitions. Therefore, non out-of-line definition of a static is forcibly made a compiler error.
Using static inline or static const remedies this. static inline only concretises the symbol if it is used in the translation unit and ensures the linker only selects and leaves one copy if it's defined in multiple translation units due to it being in a comdat group. const at file scope makes the compiler never emit a symbol because it's always substituted immediately in the code unless extern is used, which is not permitted in a class.
One thing to note is static inline int b; is treated as a definition whereas static const int b or static const A b; are still treated as a declaration and must be defined out-of-line if you don't define it inside the class. Interestingly static constexpr A b; is treated as a definition, whereas static constexpr int b; is an error and must have an initialiser (this is because they now become definitions and like any const/constexpr definition at file scope, they require an initialiser which an int doesn't have but a class type does because it has an implicit = A() when it is a definition -- clang allows this but gcc requires you to explicitly initialise or it is an error. This is not a problem with inline instead). static const A b = A(); is not allowed and must be constexpr or inline in order to permit an initialiser for a static object with class type i.e to make a static member of class type more than a declaration. So yes in certain situations A a; is not the same as explicitly initialising A a = A(); (the former can be a declaration but if only a declaration is allowed for that type then the latter is an error. The latter can only be used on a definition. constexpr makes it a definition). If you use constexpr and specify a default constructor then the constructor will need to be constexpr
#include<iostream>
struct A
{
int b =2;
mutable int c = 3; //if this member is included in the class then const A will have a full .data symbol emitted for it on -O0 and so will B because it contains A.
static const int a = 3;
};
struct B {
A b;
static constexpr A c; //needs to be constexpr or inline and doesn't emit a symbol for A a mutable member on any optimisation level
};
const A a;
const B b;
int main()
{
std::cout << a.b << b.b.b;
return 0;
}
A static member is an outright file scope declaration extern int A::a; (which can only be made in the class and out of line definitions must refer to a static member in a class and must be definitions and cannot contain extern) whereas a non-static member is part of the complete type definition of a class and have the same rules as file scope declarations without extern. They are implicitly definitions. So int i[]; int i[5]; is a redefinition whereas static int i[]; int A::i[5]; isn't but unlike 2 externs, the compiler will still detect a duplicate member if you do static int i[]; static int i[5]; in the class.
I think it's to prevent you from mixing declarations and definitions. (Think about the problems that could occur if you include the file in multiple places.)
static variables are specific to a class . Constructors initialize attributes ESPECIALY for an instance.
Requirements
I want a constexpr value (i.e. a compile-time constant) computed from a constexpr function. And I want both of these scoped to the namespace of a class, i.e. a static method and a static member of the class.
First attempt
I first wrote this the (to me) obvious way:
class C1 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar = foo(sizeof(int));
};
g++-4.5.3 -std=gnu++0x says to that:
error: ‘static int C1::foo(int)’ cannot appear in a constant-expression
error: a function call cannot appear in a constant-expression
g++-4.6.3 -std=gnu++0x complains:
error: field initializer is not constant
Second attempt
OK, I thought, perhaps I have to move things out of the class body. So I tried the following:
class C2 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar;
};
constexpr int C2::bar = C2::foo(sizeof(int));
g++-4.5.3 will compile that without complaints. Unfortunately, my other code uses some range-based for loops, so I have to have at least 4.6. Now that I look closer at the support list, it appears that constexpr would require 4.6 as well. And with g++-4.6.3 I get
3:24: error: constexpr static data member ‘bar’ must have an initializer
5:19: error: redeclaration ‘C2::bar’ differs in ‘constexpr’
3:24: error: from previous declaration ‘C2::bar’
5:19: error: ‘C2::bar’ declared ‘constexpr’ outside its class
5:19: error: declaration of ‘const int C2::bar’ outside of class is not definition [-fpermissive]
This sounds really strange to me. How do things “differ in constexpr” here? I don't feel like adding -fpermissive as I prefer my other code to be rigurously checked. Moving the foo implementation outside the class body had no visible effect.
Expected answers
Can someone explain what is going on here? How can I achieve what I'm attempting to do? I'm mainly interested in answers of the following kinds:
A way to make this work in gcc-4.6
An observation that later gcc versions can deal with one of the versions correctly
A pointer to the spec according to which at least one of my constructs should work, so that I can bug the gcc developers about actually getting it to work
Information that what I want is impossible according to the specs, preferrably with some insigt as to the rationale behind this restriction
Other useful answers are welcome as well, but perhaps won't be accepted as easily.
The Standard requires (section 9.4.2):
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.
In your "second attempt" and the code in Ilya's answer, the declaration doesn't have a brace-or-equal-initializer.
Your first code is correct. It's unfortunate that gcc 4.6 isn't accepting it, and I don't know anywhere to conveniently try 4.7.x (e.g. ideone.com is still stuck on gcc 4.5).
This isn't possible, because unfortunately the Standard precludes initializing a static constexpr data member in any context where the class is complete. The special rule for brace-or-equal-initializers in 9.2p2 only applies to non-static data members, but this one is static.
The most likely reason for this is that constexpr variables have to be available as compile-time constant expressions from inside the bodies of member functions, so the variable initializers are completely defined before the function bodies -- which means the function is still incomplete (undefined) in the context of the initializer, and then this rule kicks in, making the expression not be a constant expression:
an invocation of an undefined constexpr function or an undefined constexpr constructor outside the definition of a constexpr function or a constexpr constructor;
Consider:
class C1
{
constexpr static int foo(int x) { return x + bar; }
constexpr static int bar = foo(sizeof(int));
};
1) Ilya's example should be invalid code based on the fact that the static constexpr data member bar is initialized out-of-line violating the following statement in the standard:
9.4.2 [class.static.data] p3: ... 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.
2) The code in MvG's question:
class C1 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar = foo(sizeof(int));
};
is valid as far as I see and intuitively one would expect it to work because the static member foo(int) is defined by the time processing of bar starts (assuming top-down processing).
Some facts:
I do agree though that class C1 is not complete at the point of invocation of foo (based on 9.2p2) but completeness or incompleteness of the class C1 says nothing about whether foo is defined as far as the standard is concerned.
I did search the standard for the definedness of member functions but didn't find anything.
So the statement mentioned by Ben doesn't apply here if my logic is valid:
an invocation of an undefined constexpr function or an undefined
constexpr constructor outside the definition of a constexpr function
or a constexpr constructor;
3) The last example given by Ben, simplified:
class C1
{
constexpr static int foo() { return bar; }
constexpr static int bar = foo();
};
looks invalid but for different reasons and not simply because foo is called in the initializer of bar. The logic goes as follows:
foo() is called in the initializer of the static constexpr member bar, so it has to be a constant expression (by 9.4.2 p3).
since it's an invocation of a constexpr function, the Function invocation substitution (7.1.5 p5) kicks in.
Their are no parameters to the function, so what's left is "implicitly converting the resulting returned expression or braced-init-list to the return type of the function as if by copy-initialization." (7.1.5 p5)
the return expression is just bar, which is a lvalue and the lvalue-to-rvalue conversion is needed.
but by bullet 9 in (5.19 p2) which bar does not satisfy because it is not yet initialized:
an lvalue-to-rvalue conversion (4.1) unless it is applied to:
a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression.
hence the lvalue-to-rvalue conversion of bar does not yield a constant expression failing the requirement in (9.4.2 p3).
so by bullet 4 in (5.19 p2), the call to foo() is not a constant expression:
an invocation of a constexpr function with arguments that, when substituted by function invocation substitution (7.1.5), do not produce a constant expression
#include <iostream>
class C1
{
public:
constexpr static int foo(constexpr int x)
{
return x + 1;
}
static constexpr int bar;
};
constexpr int C1::bar = C1::foo(sizeof(int));
int main()
{
std::cout << C1::bar << std::endl;
return 0;
}
Such initialization works well but only on clang
Probably, the problem here is related to the order of declaration/definitions in a class. As you all know, you can use any member even before it is declared/defined in a class.
When you define de constexpr value in the class, the compiler does not have the constexpr function available to be used because it is inside the class.
Perhaps, Philip answer, related to this idea, is a good point to understand the question.
Note this code which compiles without problems:
constexpr int fooext(int x) { return x + 1; }
struct C1 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar = fooext(5);
};
constexpr static int barext = C1::foo(5);