Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static constexpr pointer-to-function, difference between compilers

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
  1. Which compiler is right ?
  2. If clang is right, why , and what does this error really means ?

EDIT: for the "why", see DyP's question.

like image 990
Synxis Avatar asked Apr 07 '13 20:04

Synxis


People also ask

Does constexpr need to be static?

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. So, what does constexpr mean?

What is the difference between const and constexpr?

The primary difference between const and constexpr variables is that the initialization of a const variable can be deferred until run time. A constexpr variable must be initialized at compile time. All constexpr variables are const .

What does constexpr const mean?

constexpr creates a compile-time constant; const simply means that value cannot be changed.

What is constexpr function in C++?

constexpr stands for constant expression and is used to specify that a variable or function can be used in a constant expression, an expression that can be evaluated at compile time. The key point of constexpr is that it can be executed at compile time.


1 Answers

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`
like image 141
dyp Avatar answered Oct 20 '22 00:10

dyp