I have the following piece of code which compiles on older gcc, but not on version 6 (works with -std=c++1z). Clang rejects it too, saying the object val doesn't have the right kind of linkage. I don't understand the difference. Isn't a constexpr variable of a pointer type supposed to work more or less transparently? Is there something I'm missing in the syntax that would allow this to work? Or is this violating some portion of the standard?
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
static constexpr t_voidfn val = &fn;
s<val> x;
}
On the other hand this one works.
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
s<&fn> x;
}
constexpr int a = 2; Static specifies the lifetime of the variable. A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.
constexpr functions are implicitly inline , but not implicitly static .
constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.
According to the proposal, an object created within a constexpr expression, can now be changed during the evaluation process - until the evaluation process or the object's lifetime ends.
The first snippet is correct in C++17, but not in C++14 and 11.
For C++14, [temp.arg.nontype]/1 says:
A template-argument for a non-type, non-template template-parameter shall be one of:
[...]
- a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as
&
id-expression, where the id-expression is the name of an object or function, except that the&
may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or- a constant expression that evaluates to a null pointer value (4.10); or
- a constant expression that evaluates to a null member pointer value (4.11); or
- a pointer to member expressed as described in 5.3.1; or
- a constant expression of type
std::nullptr_t
.
(I've included only the bullets that are directly relevant to pointers and pointers to members.)
Basically, the address of the function in your sample has to be expressed strictly as &fn
or fn
.
C++11 contains essentially the same wording minus a couple of clarifications introduced by defect reports between 11 and 14:
For C++17, the restrictions have been relaxed as a result of the adoption of paper N4268 (rationale in N4198). The corresponding paragraph (2) now says:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
- a subobject (1.8),
- a temporary object (12.2),
- a string literal (2.13.5),
- the result of a
typeid
expression (5.2.8), or- a predefined
__func__
variable (8.4.1).[ Note: If the template-argument represents a set of overloaded functions (or a pointer or member pointer to such), the matching function is selected from the set (13.4). — end note ]
N4198 contains good explanations for each of those bullets.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With