VC++ 2015 error: "an expression involving objects with internal linkage cannot be used as a non-type argument"

160 views Asked by At

The following sample code does compiles in VC++ 2019, clang++ and g++ but not VC++ 2015.

namespace ns
{
    template<const char* str>
    struct Foo
    {
    };
    
    static const char name[] = "Test";
    Foo<name> foo;
}

int main()
{
}

Are there any workarounds for VC++ 2015? I'm assuming the code is conforming but VC++ 2015 had a bug which was fixed in VC++ 2019. I'd migrate to VC++ 2019 but my company builds in VC++ 2015.

2

There are 2 answers

2
rustyx On BEST ANSWER

MSVC 2015 doesn't fully support C++11, and non-type template arguments with internal linkage is an example of a C++11 feature which VC++ didn't support until version 14.14 (VS 2017 15.8).

I can think of 3 solutions:

  • Don't use template arguments with internal linkage by removing static const specifiers from char name[]
  • Upgrade the compiler to VC++ 14.20+ (MSVC 2019)
  • Use feature detection and/or conditional compilation

Regarding conditional compilation, it can be achieved like this:

#if !defined(_MSC_VER) || _MSC_VER > 1914 // this part can be in a global config.h
#  define INTERNAL static const
#else
#  define INTERNAL 
#endif

namespace ns
{
    template<const char* str>
    struct Foo
    {};
    
    INTERNAL char name[] = "Test";
    Foo<name> foo;
}

int main()
{
}
0
Adrian Mole On

As mentioned in the comments, the issue lies with the fact that VS-2015 does not comply with the C++11 Standard, which is required to implement the code you have shown.

Looking at how the issue is described in this report, the only way I have found to resolve the issue is to remove both the static and const qualifiers in your declaration of name. The following compiles even with the VS-2010 build tools (I don't have access to the VS-2015 tools on my PC but, as this works with both VS-2010 and VS-2019, I assume it would also be OK in VS-2015).

namespace ns {
    template<const char* str>
    struct Foo {
    };

    char name[] = "Test"; // Adding either "static" or "const" causes C2970
    Foo<name> foo;
}

int main()
{
}

Whether or not this workaround is suitable for your needs remains to be seen.