11

I can't seem to use local static values as template arguments, in C++11. For example:

#include <iostream>
using namespace std;

template <const char* Str>
void print() {
  cout << Str << endl;
}

int main() {
  static constexpr char myStr[] = "Hello";
  print<myStr>();
  return 0;
}

In GCC 4.9.0, the code errors with

error: ‘myStr’ is not a valid template argument of type ‘const char*’ because ‘myStr’ has no linkage

In Clang 3.4.1, the code errors with

candidate template ignored: invalid explicitly-specified argument for template parameter 'Str'

Both compilers were run with -std=c++11

A link to an online compiler where you can select one of many C++ compilers: http://goo.gl/a2IU3L

Note, moving myStr outside main compiles and runs as expected.

Note, I have looked at similar StackOverflow questions from before C++11, and most indicate that this should be resolved in C++11. For example Using local classes with STL algorithms

Community
  • 1
  • 1
user108088
  • 1,128
  • 2
  • 16
  • 29
  • 3
    I think [EWG issue 155/N4198](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4198.html) explains this very well, in particular *"the restriction to entities with linkage is an artifact of exported templates, and could have been removed when the linkage restrictions on template type parameters were removed"* – Piotr Skotnicki Nov 17 '14 at 08:57
  • As far as I can make out, a variable declared at block scope (in this case function variable) has no linkage unless declared `extern`, in which case is has external linkage. I'm not sure there is a way to declare block scope variable with internal linkage. – Niall Nov 17 '14 at 09:05
  • @PiotrS. I can't tell which version of C++ [EWG issue 155/N4198] is referring to. Is it for C++11? – user108088 Nov 17 '14 at 09:41
  • 2
    It's a paper dated 2014-10-06; it is a proposal for future language evolution and concerns the restrictions imposed on the language by the most recent C++ standard. In other words, as of now your `myStr` is an address of an object with *no linkage* (although it has a static storage duration) hence not allowed as a non-type template argument by the standard. It is proposed to remove the "linkage" constraint, so that an address of the object with static storage duration will be a constant expression allowed as a non-type template argument. – Piotr Skotnicki Nov 17 '14 at 10:04
  • [Apparently](https://gcc.godbolt.org/z/tCtT4e) your code example is compiled by newer compilers (gcc 7.2 or newer) and newer language dialect (C++17 or newer). – user5534993 Feb 12 '19 at 17:02

1 Answers1

3

Apparently "no linkage" means "The name can be referred to only from the scope it is in." including local variables. Those aren't valid in template parameters because their address isn't known at compile time apparently.

Easy solution is to make it a global variable. It doesn't really change your code.

See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52036

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 3
    The code above is simplified from the original context. In my actual code, I have a macro that creates both lines: the const string and the function call. The macro cannot create a global variable and a local function call. – user108088 Nov 17 '14 at 08:35
  • Regarding the gcc bug, any idea why clang would fail in the same way? – user108088 Nov 17 '14 at 08:37
  • 1
    @user108088 Same bug in clang? – BЈовић Nov 17 '14 at 08:57
  • @user108088. I think this gcc bug is the `static` vs. `extern`. Clang accepts the internal vs. external linkage, gcc sees the `static` has having no linkage. http://coliru.stacked-crooked.com/a/2d93fe317886484d – Niall Nov 17 '14 at 09:02
  • 2
    @BЈовић If this is a bug in gcc, than I would expect another, independently produced, compiler would be unlikely to have the same bug. Clang doesn't compile the code either. – user108088 Nov 17 '14 at 09:35