对静态constexpr字符串的未定义引用(除非是指针) [英] Undefined reference to static constexpr string (except if it's a pointer)

查看:81
本文介绍了对静态constexpr字符串的未定义引用(除非是指针)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这项工作:

template<typename T> struct Something
{ static constexpr const char* str = "int"; };

int main()
{ std::cout << Something<int>::str << std::endl; }

但事实并非如此:

template<typename T> struct Something
{ static constexpr const char str[] = "int"; };

int main()
{ std::cout << Something<int>::str << std::endl; }

gcc-4.8 说:未定义引用 Something< int> :: str

可以解决此错误,方法是在外部定义静态成员类别:

This error can be solved defining the static member outside of the class:

template<typename T>
constexpr const char Something<T>::name[];

为什么它不是必需的指针,而是数组?毕竟,两者都是静态constexpr 成员。

Why isn't it neccesary with pointers but with arrays? Both are static constexpr members after all.

推荐答案

对象或函数如果已使用,则必须定义。在某些情况下,对象和函数不会被滥用,在这种情况下,您不必定义它们。静态类成员的声明是否具有初始化程序,仍然不是定义。在所有情况下,规则都是:如果使用静态成员,则必须在封闭的命名空间范围内使用类外定义。

An object or function must be defined if it is odr-used. In some cases objects and functions are not odr-used and in those cases you don't have to define them. Whether or not the declaration of a static class member has an initializer, it is still not a definition. In all cases the rule is that an out-of-class definition at an enclosing namespace scope is required if the static member is odr-used.

直觉是 odd-used表示链接器需要其地址。如果 constexpr 变量仅以需要其值的方式(而不是其地址)使用,则可以避免被过度使用。在这种情况下,编译器只是内联其值,并且不需要定义它,因为链接器不需要其地址。 const char * Something< int> :: str 就是这种情况,但 const char Something< int> :: str []

The intuition is that "odr-used" means "the linker needs its address". If a constexpr variable is only used in ways that require its value---and never its address---then it may avoid being odr-used. In such cases the compiler simply inlines its value, and it does not need to be defined, because the linker doesn't need its address. That's the case with const char* Something<int>::str, but not const char Something<int>::str[].

但是它们是相同的!,你大喊。不是这样对于 str const char * 的情况,其地址字符串文字 int 。需要字符串文字的地址,但不需要 str 本身的地址。前者是 str 的值,它满足 not 不能被滥用的要求;编译器可以内联它。但是,当 str const char [] 时,其是字符串文字 int 本身。当您尝试使用 istream :: operator<< 输出时,它隐式转换为 const char * 。但是 const char * 是字符串文字的地址,即 Something< int> :: str 。因此,在这种情况下,使用 Something< int> :: str 即可;

"But they're the same!", you shout. Not so. For when str is a const char*, its value is the address of the string literal "int". The address of the string literal is needed, but not the address of str itself. The former is the value of str and it satisfies the requirements for not being odr-used; the compiler can just inline it. But when str is a const char[], its value is the string literal "int" itself. When you try to output it using istream::operator<<, it is implicitly converted into a const char*. But the const char*'s value is the address of the string literal, that is, the address of Something<int>::str. Therefore in this case Something<int>::str is odr-used; its address is needed.

标准中有逻辑可以用来精确确定何时使用变量([basic.def.odr])。但我不会引用它,因为它是整个标准中最令人困惑的部分。我要说的是,如果您有 const char * Something< int> :: str ,则会立即应用左值到右值转换,这是其中之一不被滥用的条件;并且在您具有 const char Something< int> :: str [] 的情况下,将立即应用数组到指针的转换,这不能满足条件。

There is logic in the standard that can be used to determine precisely when a variable is odr-used ([basic.def.odr]). But I'm not going to quote it because it's the most confusing section of the entire standard. I will say that in the case where you have const char* Something<int>::str, the lvalue-to-rvalue conversion is immediately applied, which is one of the conditions for it to not be odr-used; and in the case where you have const char Something<int>::str[], the array-to-pointer conversion is immediately applied, and that doesn't satisfy the condition.

这篇关于对静态constexpr字符串的未定义引用(除非是指针)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆