C++ 静态常量成员变量、变量模板和&;的编译器错误或正确行为&;?
我在编译下面包含的代码时注意到一个奇怪的行为。我有4个文件如下 createshared.h: staticinitclass.cpp: 很好,因为默认的_i是一个整数类型,所以我们可以在头中初始化它。让我们这样做 很好,仍然编译并工作良好。现在,让我们添加&&和std::forward 链接器错误。现在,让我们尝试初始化.cpp中的默认_i成员 它又起作用了。使用clang也会产生同样的结果,这让我相信这不仅仅是一个孤立的编译器错误,而且可能是语言本身的某些东西阻止了静态初始化。我似乎无法理解为什么添加&会导致中断 目前我正在Ubuntu 14.04上使用g++4.8.2和clang++3.5C++ 静态常量成员变量、变量模板和&;的编译器错误或正确行为&;?,c++,c++11,rvalue-reference,compiler-bug,C++,C++11,Rvalue Reference,Compiler Bug,我在编译下面包含的代码时注意到一个奇怪的行为。我有4个文件如下 createshared.h: staticinitclass.cpp: 很好,因为默认的_i是一个整数类型,所以我们可以在头中初始化它。让我们这样做 很好,仍然编译并工作良好。现在,让我们添加&&和std::forward 链接器错误。现在,让我们尝试初始化.cpp中的默认_i成员 它又起作用了。使用clang也会产生同样的结果,这让我相信这不仅仅是一个孤立的编译器错误,而且可能是语言本身的某些东西阻止了静态初始化。我似
在§9.4.2[类.静态.数据]之后使用-dinInitialize_IN_HEADER和-DUSE_refrefref?时,这里有什么问题 3如果非易失性常量静态数据成员是整型或枚举型,则其在类定义中的声明可以指定一个大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式(5.19)。[…]如果在程序中使用odr(3.2),则仍应在名称空间范围中定义成员,并且名称空间范围定义不应包含初始值设定项。 换句话说,在头中直接给const静态数据成员一个值并不意味着不需要定义该数据成员。您应该在staticinitclass.cpp文件中包含以下内容:
#ifndef INITIALIZE_IN_HEADER
const int StaticInitClass::default_i = 2;
#else
const int StaticInitClass::default_i; // this is what you don't have
#endif
绑定到引用(在您的情况下,绑定到转发引用&&
被推断为常量左值引用)算作此数据成员的odr使用
如果您不使用转发引用,并且按值获取参数,则它不是该静态数据成员的odr使用,因此不会引发链接器错误。为静态数据成员提供初始值设定项并不意味着您还提供了定义。当您将两个
-D
选项组合在一起时,最终导致odr使用该静态成员,因此需要为其提供一个定义。缺少的部分是,仅使用该值不算作odr使用。@t.C.也添加了这个!我完全不知道odr使用的规范。谢谢
#ifndef STATICINITCLASS_H_
#define STATICINITCLASS_H_
class StaticInitClass
{
public:
#ifdef INITIALIZE_IN_HEADER
static const int default_i = 1;
#else
static const int default_i;
#endif
virtual ~StaticInitClass() = default;
StaticInitClass() = delete;
protected:
StaticInitClass(int i);
};
#endif
#include "staticinitclass.h"
#include <iostream>
#ifndef INITIALIZE_IN_HEADER
const int StaticInitClass::default_i = 2;
#endif
StaticInitClass::StaticInitClass(int i)
{
std::cout << "Created with " << i << std::endl;
}
#include "staticinitclass.h"
#include "createshared.h"
#include <memory>
int main(int argc, const char* argv[])
{
auto shared = create_shared<StaticInitClass>(StaticInitClass::default_i);
}
$ g++ -std=c++11 main.cpp staticinitclass.cpp
$ ./a.out
Created with 2
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER
$ ./a.out
Created with 1
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER -DUSE_REFREF
/tmp/cc3G4tjc.o: In function `main':
main.cpp:(.text+0xaf): undefined reference to `StaticInitClass::default_i'
collect2: error: ld returned 1 exit status
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DUSE_REFREF
$ ./a.out
Created with 2
#ifndef INITIALIZE_IN_HEADER
const int StaticInitClass::default_i = 2;
#else
const int StaticInitClass::default_i; // this is what you don't have
#endif