I don't understand why if I initialize this template variable globally, like this:
template <class T> struct null_string { static const std::string value; };
template<class T> const std::string null_string<T>::value = "";
template<class T> std::string const null_str = null_string<const T&>::value;
it works, but if I try to initialize it inside a class, like this:
class foo
{
template <class T> struct null_string { static const std::string value; };
template<class T> const std::string null_string<T>::value = "";
template<class T> std::string const null_str = null_string<const T&>::value;
};
it gave me an error:
prove.cpp:8:65: error: invalid use of qualified-name ‘foo::null_string<T>::value’
8 | template<class T> const std::string null_string<T>::value = "";
| ^~
prove.cpp:11:78: error: data member ‘null_str’ cannot be a member template
11 | template<class T> std::string const null_str = null_string<const T&>::value;
|
Do you know why?
CodePudding user response:
Add missing static
. Then, either move variable definitions to namespace scope:
class foo
{
template <class T> struct null_string { static const std::string value; };
template <class T> static std::string const null_str;
};
template <class T> const std::string foo::null_string<T>::value = "";
template <class T> std::string const foo::null_str = foo::null_string<const T&>::value;
Or make them inline:
class foo
{
template <class T> struct null_string { inline static const std::string value = ""; };
template <class T> inline static const std::string null_str = foo::null_string<const T&>::value;
};
CodePudding user response:
The problem is that you're providing the definition for the static data member in class-scope instead of namespace scope when the definition for a static data member must be placed in a namespace scope enclosing the member’s class definition. This can be seen from class.static.data#3 which states:
The declaration of a non-inline static data member in its class definition is not a definition and may be of an incomplete type other than cv void. The definition for a static data member that is not defined inline in the class definition shall appear in a namespace scope enclosing the member's class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator.
(emphasis mine)
Thus the correct way to do what you want would be as shown below:
class foo
{
template <class T> struct null_string
{
static const std::string value; //declaration not a definition
};
//------------------vvvvvv---------------------------->added static here
template<class T> static std::string const null_str;//declaration not a definition
};
//provide definition for static members at global scope
template<class T> const std::string foo::null_string<T>::value = "";
template<class T> std::string const foo::null_str = foo::null_string<const T&>::value;
With C 17, you can also use inline
to provide in-class definition for the static data members.
class foo
{
template <class T> struct null_string
{
//----vvvvvv---------------------------------> inline used here
inline static const std::string value = ""; //definition
};
//--------------------------vvvvvv--------------------------->added static here
template<class T> inline static std::string const null_str = foo::null_string<const T&>::value;//definition
//------------------^^^^^^----------------------------------->inline used here
};