3

I'm trying to create a parameter pack with a default pointer type:

template<int*... T>
void f() {}

I get error with this code:

int main(){
    int* a = new int(5);
    f<a>();
}

But if I do this, I don't get a error:

int main(){
    f<nullptr>();
}

Why?

Error:

./example.cpp: In function 'int main()': ./example.cpp:6:7: error: the
value of 'a' is not usable in a constant expression
     f<a>();
       ^ ./example.cpp:5:10: note: 'a' was not declared 'constexpr'
     int* a = new int;
          ^ ./example.cpp:6:10: error: no matching function for call to 'f<a>()'
     f<a>();
          ^ ./example.cpp:2:6: note: candidate: 'template<int* ...T> void f()'  void f() {}
      ^ ./example.cpp:2:6: note:   template argument deduction/substitution failed: ./example.cpp:6:10: error: 'a' is not a
valid template argument because 'a' is a variable, not the address of
a variable
     f<a>();
          ^ Compiler returned: 1

Compiler Explorer

João Paulo
  • 6,300
  • 4
  • 51
  • 80
  • Possible duplicate of [using an absolute pointer address as a template argument](https://stackoverflow.com/questions/37303968/using-an-absolute-pointer-address-as-a-template-argument) – Richard May 17 '19 at 20:44
  • 1
    @Richard that problem stems from using a C-style cast on an integer literal, while this question is using `new` instead – alter_igel May 17 '19 at 20:48
  • 1
    For what it's worth, `static int a {}; f<&a>();` works just fine. – alter_igel May 17 '19 at 20:50

1 Answers1

3

An argument for non-type template parameter must be constant expression.

int* a = new int(5);

In this snippet, a is not a constant expression, and not suitable for template non-type parameter.

As a matter of fact, this should be intuitively acceptable. Remember, compiler needs to generate code for instantiated template before program can be executed, and this code would have to use the value of template argument. But value of a is not known at compile time - it could be anything, depending on where the memory would be allocated. Obviously, compiler can't predict what value would it be.

On the other hand, address of a global (or function static) object can be used as non-type pointer template argument:

int k = 10;

int main(){
    f<&k>();
}

The code above works, which intuitively makes sense, since compiler would know where the global object lives (compiler will put it there itself!)

Last, but not the least, your title is unnecessary narrow. Those rules apply to non-variadic templates the same way.

SergeyA
  • 61,605
  • 5
  • 78
  • 137