Consider following
struct dummy{};
dummy d1;
dummy d2;
template<dummy* dum>
void foo()
{
if (dum == &d1)
; // do something
else if (dum == &d2)
; // do something else
}
Now, it is possible to call foo
like this
foo<&d1>();
foo<&d2>();
and everything works as expected. But following does not
constexpr dummy* dum_ptr = &d1;
foo<dum_ptr>();
With this error from Visual studio
error C2975:
dum_ptr
: invalid template argument forfoo
, expected compile-time constant expression
While this works
constexpr dummy& dum_ref = d1;
foo<&dum_ptr>();
In visual studio, but not in G++, because of
note: template argument deduction/substitution failed:
error:& dum_ref
is not a valid template argument fordummy*
because it is not the address of a variablefoo<&dum_ref>();
EDIT:
Since C++17, std::addressof
is being marked as constexpr, so I would guess it should work.
constexpr implies const and const on global/namespace scope implies static (internal linkage), which means that every translation unit including this header gets its own copy of PI.
The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.
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.
#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.
GCC is right on this one.
The expressions are definitely constant-expression
s*, since they are assigned to a constexpr
variable. However, until c++14, there are additional restrictions on what is allowed for a pointer template argument.
C++14 draft N4140 [temp.arg.nontype]
1 A template-argument for a non-type, non-template template-parameter shall be one of:
- for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the template-parameter; or
- the name of a non-type template-parameter; or
- 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.
For foo<dum_ptr>()
, dum_ptr
isn't expressed as &name
, and for foo<&dum_ref>()
, dum_ref
isn't the name of the object, it's the name of a reference to the object, so both are disallowed as template arguments.
These restrictions are lifted in c++17 to allow any constexpr, so thats why it works there:
C++17 draft N4606 - 14.3.2 Template non-type arguments [temp.arg.nontype]
1 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):
- (1.1) a subobject (1.8),
- (1.2) a temporary object (12.2),
- (1.3) a string literal (2.13.5),
- (1.4) the result of a typeid expression (5.2.8), or
- (1.5) a predefined __func__ variable (8.4.1).
As usual, clang gives the best error messages: https://godbolt.org/g/j0Q2bV
*(see Address constant expression and Reference constant expression)
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