8
votes

Look at this piece of code:

#include <string>
#include <iostream>
using namespace std;

template <typename T, const T& temp>
void g()
{
    cout << temp << endl;
}

static const std::string s = "abc";

int main() {
    g<string, s>();
}

When I compile this with Visual C++ 2013 November CTP I get:

“error C2970: 'g' : template parameter 'temp' : 's' : an expression involving objects with internal linkage cannot be used as a non-type argument”

However, I read the following in the C++ 14 standard (14.3.2 [temp.arg.nontype]):

“a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or”

I interpret this as “constant expression with static storage duration and external linkage” or “constant expression with static storage duration and internal linkage”. In my example above, isn’t the variable s a “constant expression with static storage duration and internal linkage” ?

When I change s to:

std::string s = "abc";

Then it compiles and it works, but isn’t that against the standard because now s is not a “constant expression” anymore.

Can someone shed some light on this? Am I misinterpreting something here?

2
Try namespace { const std::string s = "abc"; }?Yakk - Adam Nevraumont
I tested your code on c++builder XE6 64bit and work. C++builder xe6 64bit uses a modified version of the CLang compatible with C11.AngeloDM
@Yakk That doesn't work either. It's complaining about internal linkage. extern const ... does work.Praetorian
@Yakk: const objects declared at namespace level has internal linkage (unless it is declared extern).Nawaz

2 Answers

11
votes

Replace static with extern:

extern const std::string s = "abc";

The reason is that in C++98/C++03, references with internal linkage was not allowed as template argument.

Also note that just removing static only would not work if const is there, because const objects declared at namespace level has internal linkage (unless it is declared extern). So you need to use extern as shown above.

8
votes

In C++98 the language was (from 14.3.2/1): the name of an object or function with external linkage.... The change to allow internal linkage was included in C++11.

Your compiler is probably only compiling as the C++98 (or 03) standard, not C++11.