When answering this question, I tried the following code with gcc (code compiled) and clang (code rejected):
typedef long (*func)(int);
long function(int) { return 42; }
struct Test
{
static constexpr func f = &function;
};
template<func c>
struct Call
{
static void f()
{
c(0);
}
};
int main()
{
Call<Test::f>::f();
}
I am not sure which compiler is right, although I think the constexpr initialization of Test::f
is ok. The error clang outputs is:
error: non-type template argument for template parameter of pointer type 'func'
(aka 'long (*)(int)') must have its address taken
- Which compiler is right ?
- If clang is right, why , and what does this error really means ?
EDIT: for the "why", see DyP's question.
14.3.2 Template non-type arguments [temp.arg.nontype]
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 an 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, 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; [...]
(n3485, emphasis mine)
I don't know exactly why it's been limited, but I think it might be related to the fact that the function address is not available at compile time (there might be a substitute for template instantiation purposes).
Edit: Enhanced answer due to a follow-up question (comment) of Synxis
constexpr func = &function;
^ this is well-formed; you can use the address of a function to initialize a constexpr
object.
The problem is that it's explicitly forbidden to use pointers as non-type template arguments other than of the form &identifier
:
using My_Call = Call < &function >; // fine
constexpr func mypointer = &function; // fine
using My_Ind_Call = Call < func >; // forbidden, argument not of form `&id`