Static member access in constant expressions
Clang seems to be in the right. When accessing a static member with the member access syntax [class.static/1]:
A static member s of class X may be referred to using the qualified-id
expression X::s; it is not necessary to use the class member access
syntax to refer to a static member. A static member may be referred to
using the class member access syntax, in which case the object
expression is evaluated.
So s.v()
will cause s
to be evaluated. Now, according to [expr.const/2.11], s
is not a constant expression:
2 An expression e is a core constant expression unless the evaluation
of e, following the rules of the abstract machine, would evaluate one
of the following expressions:[...]
an id-expression that refers to a variable or data member of reference
type unless the reference has a preceding initialization and either:
(2.11.1) - it is initialized with a constant expression or
(2.11.2) - its lifetime began within the evaluation of e;
s
doesn't have a preceding initialization with a constant expression, not in the scope of foo
.
If you want to access the static members based of a function parameter, without hard-coding the type, the way forward is std::remove_reference_t<decltype(s)>
. This is accepted by Clang and GCC both:
#include <type_traits>
struct S
{
constexpr static auto s_v = 42;
constexpr static auto v() { return s_v; }
};
constexpr auto foo(S const& s)
{
constexpr auto v = std::remove_reference_t<decltype(s)>::v();
return v;
}
constexpr auto bar(S const& s)
{
constexpr auto v = std::remove_reference_t<decltype(s)>::s_v;
return v;
}
int main() {}
Accessing a static constexpr member from a member variable, GCC bug?
GCC is correct. A template argument must be a constant expression, and a.n
implicitly means this->a.n
since a
is a member of the enclosing class. But a constant expression evaluation cannot access this
inside a non-constexpr
member function ([expr.const]/2.1). And even though evaluating this
appears unnecessary in order to obtain the value of the static member n
, the standard requires that a
(which means this->a
) be evaluated even though its value is not needed; see [expr.ref]/1 and its footnote.
GCC will accept your code if func
is marked constexpr
. As pointed out in the comments, it's better to just write A::n
, though.
How to access the address of a static const member of a class?
Put
const int A::a;
In the source file, otherwise the compiler doesn't generate an address for a. Note the value is not repeated here.
Constexpr static member function usage
Looks like a bug to me.
The type and meaning of the expression h.size()
is defined by [expr.ref]
"Class member access":
[expr.post]/3
Abbreviating postfix-expression.id-expression as
E1.E2
,E1
is called the object expression. [...]
and
[expr.post]/6.3.1
If
E2
is a (possibly overloaded) member function, function overload resolution is used to determine whetherE1.E2
refers to a static or a non-static member function.
- (6.3.1) If it refers to a static member function and the type of
E2
is “function of parameter-type-list returningT
”, thenE1.E2
is an lvalue; the expression designates the static member function. The type ofE1.E2
is the same type as that ofE2
, namely “function of parameter-type-list returningT
”.
This means h.size
has the same type as ::MyClass::size
and is evaluated as such, regardless of the fact that h
is constexpr
or not.
h.size()
is then a call to a constexpr
function and is a core constant expression according to [expr.const]/4
.
Cannot access static member variable from class in array
Unfortunately, you can't refer to another variable or class in the initial declaration of a class property. It's just a limitation of the language as it stands. The general workaround is to initialise the property in the constructor, e.g.
class Bar
{
public $someArray = array();
public function __construct()
{
$this->someArray = array(
Foo::$staticVar
);
}
}
On a vaguely related note, PHP 5.6 did at least make some vague headway in allowing you to define constants as basic expressions, see https://3v4l.org/6TDZV
Constant expression initializer for static class member of type double
In C++03 we were only allowed to provide an in class initializer for static member variables of const integral of enumeration types, in C++11 we could initialize a static member of literal type in class using constexpr. This restriction was kept in C++11 for const variables mainly for compatibility with C++03. We can see this from closed issue 1826: const floating-point in constant expressions which says:
A const integer initialized with a constant can be used in constant expressions, but a const floating point variable initialized with a constant cannot. This was intentional, to be compatible with C++03 while encouraging the consistent use of constexpr. Some people have found this distinction to be surprising, however.
CWG ended up closing this request as not a defect(NAD), basically saying:
that programmers desiring floating point values to participate in constant expressions should use constexpr instead of const.
For reference N1804
the closest draft standard to C++03 publicly available in section 9.4.2
[class.static.data] says:
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.
and the draft C++11 standard section 9.4.2
[class.static.data] says:
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. [...]
this is pretty much the same in the draft C++14 standard.
constexpr initializing static member using static function
The Standard requires (section 9.4.2):
A
static
data member of literal type can be declared in the class definition with theconstexpr
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 undefinedconstexpr
constructor outside the definition of aconstexpr
function or aconstexpr
constructor;
Consider:
class C1
{
constexpr static int foo(int x) { return x + bar; }
constexpr static int bar = foo(sizeof(int));
};
Related Topics
Compiling a Simple Parser with Boost.Spirit
How Would You Implement a Basic Event-Loop
Differencebetween a Static and Const Variable
Why Is the Volatile Qualifier Used Through Out Std::Atomic
Initializing Default Values in a Struct
Configuring the Gcc Compiler Switches in Qt, Qtcreator, and Qmake
Best Way for Interprocess Communication in C++
How to Copy/Paste from the Clipboard in C++
Errors When Linking to Protobuf 3 on Ms Visual C
Compiling with G++ Using Multiple Cores
How to See the Template Instantiated Code by C++ Compiler
C++ Undefined References with Static Library
Why Doesn't Emplace_Back() Use Uniform Initialization
Constexpr Const VS Constexpr Variables
What Happens When I Mix Signed and Unsigned Types
What's the Motivation Behind Having Copy and Direct Initialization Behave Differently