尝试编译以下代码时,我注意到了一个奇怪的行为。我有4个文件,如下所示
createshared.h:
#ifndef CREATESHARED_H_
#define CREATESHARED_H_
#include <memory>
#include <utility>
#ifdef USE_REFREF
template<typename T, typename... Args>
std::shared_ptr<T> create_shared(Args&&... args)
{
class HelperClass : public T
{
public:
HelperClass (Args&& ... nargs) : T(std::forward<Args...>(nargs)...) {}
virtual ~HelperClass() = default;
};
return std::make_shared<HelperClass>(std::forward<Args...>(args)...);
}
#else
template<typename T, typename... Args>
std::shared_ptr<T> create_shared(Args... args)
{
class HelperClass : public T
{
public:
HelperClass (Args ... nargs) : T(nargs...) {}
virtual ~HelperClass() = default;
};
return std::make_shared<HelperClass>(args...);
}
#endif
#endif
staticinitclass.h
#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
staticinitclass.cpp:
#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;
}
main.cpp:
#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
很好,因为default_i是整数类型,我们可以在标头中对其进行初始化。来做吧
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER
$ ./a.out
Created with 1
很好,仍然可以编译并且可以正常工作。现在,让我们添加&&和std :: forward
$ 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
链接器错误。好吧,现在让我们尝试在.cpp中初始化我们的default_i成员
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DUSE_REFREF
$ ./a.out
Created with 2
并且它再次起作用。使用clang会产生相同的结果,这使我相信这不仅是一个孤立的编译器错误,而且可能是语言本身中的某些阻止静态初始化的错误。我似乎无法说明为什么添加&&会导致中断。
当前我在Ubuntu 14.04上使用g ++ 4.8.2和clang ++ 3.5
有什么想法在使用-DINITIALIZE_IN_HEADER和-DUSE_REFREF时有什么问题吗?
遵循第9.4.2节[class.static.data]:
3如果非易失性const静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定大括号或相等初始化器,其中作为赋值表达式的每个初始化器子句都是一个常数表达式(5.19 )。[...]如果在程序中使用了成员(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
绑定到引用(&&
在您的情况下,将其转发为const lvalue引用)将视为对该数据成员的odr-use。
如果您不使用转发引用,而是使用参数by-value,那么它不是对该静态数据成员的odr-use,因此不会引发链接器错误。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句