静态const成员变量,可变参数模板和&&的编译器错误或正确行为

电子

尝试编译以下代码时,我注意到了一个奇怪的行为。我有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时有什么问题吗?

皮特·斯科特尼克(Piotr Skotnicki)

遵循第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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

可变参数模板和函数的指针:哪种编译器正确?

来自分类Dev

模板元编程,带有可变参数模板:编译器错误

来自分类Dev

具有可变参数模板的模板元编程:编译器错误

来自分类Dev

静态成员初始化和可变参数模板

来自分类Dev

哪个编译器关于使用Singleton CRTP的模板参数类型的内联静态成员是正确的?

来自分类Dev

内部编译器错误:gcc中的分段错误。发送可变参数模板到结构时

来自分类Dev

内部编译器错误:gcc中的分段错误。发送可变参数模板到结构时

来自分类Dev

编译器无法推断可变参数模板的模板参数

来自分类Dev

编译器错误,还是非标准代码?-Lambda中的可变参数模板捕获

来自分类Dev

模板容器的const函数中的编译器错误修改成员变量

来自分类Dev

为什么Clang ++编译器无法编译以下可变参数模板代码?

来自分类Dev

C ++将模板参数包从一个可变参数模板传递到另一个可变参数模板会导致编译器错误

来自分类Dev

可变参数模板能否与当前的编译器正常工作?

来自分类Dev

是编译器还是我自己:从包含lambda的可变参数模板继承

来自分类Dev

编译器跳过C ++中的可变参数模板/函数

来自分类Dev

可变参数模板的链接器错误

来自分类Dev

在类中嵌套静态const成员变量初始化Clang vs GCC哪个编译器正确?

来自分类Dev

模板成员函数的编译器错误

来自分类Dev

类型擦除和可变参数模板化成员函数

来自分类Dev

可变参数模板和std :: array意外行为

来自分类Dev

VS2013可变参数模板编译错误

来自分类Dev

可变参数模板的静态继承

来自分类Dev

Schwarz计数器和可变参数模板

来自分类Dev

可变参数模板类-可变参数成员函数

来自分类Dev

g ++和clang具有递归可变参数模板位集创建的不同行为(可能是gcc错误?)

来自分类Dev

可变参数模板的正确语法

来自分类Dev

可变参数模板模板参数和GCC,Clang和MSVC中的sizeof差异-谁是正确的?

来自分类Dev

可变参数模板参数和策略

来自分类Dev

可变参数函数模板接受任何指针(指向变量,函数,成员函数等)作为参数

Related 相关文章

  1. 1

    可变参数模板和函数的指针:哪种编译器正确?

  2. 2

    模板元编程,带有可变参数模板:编译器错误

  3. 3

    具有可变参数模板的模板元编程:编译器错误

  4. 4

    静态成员初始化和可变参数模板

  5. 5

    哪个编译器关于使用Singleton CRTP的模板参数类型的内联静态成员是正确的?

  6. 6

    内部编译器错误:gcc中的分段错误。发送可变参数模板到结构时

  7. 7

    内部编译器错误:gcc中的分段错误。发送可变参数模板到结构时

  8. 8

    编译器无法推断可变参数模板的模板参数

  9. 9

    编译器错误,还是非标准代码?-Lambda中的可变参数模板捕获

  10. 10

    模板容器的const函数中的编译器错误修改成员变量

  11. 11

    为什么Clang ++编译器无法编译以下可变参数模板代码?

  12. 12

    C ++将模板参数包从一个可变参数模板传递到另一个可变参数模板会导致编译器错误

  13. 13

    可变参数模板能否与当前的编译器正常工作?

  14. 14

    是编译器还是我自己:从包含lambda的可变参数模板继承

  15. 15

    编译器跳过C ++中的可变参数模板/函数

  16. 16

    可变参数模板的链接器错误

  17. 17

    在类中嵌套静态const成员变量初始化Clang vs GCC哪个编译器正确?

  18. 18

    模板成员函数的编译器错误

  19. 19

    类型擦除和可变参数模板化成员函数

  20. 20

    可变参数模板和std :: array意外行为

  21. 21

    VS2013可变参数模板编译错误

  22. 22

    可变参数模板的静态继承

  23. 23

    Schwarz计数器和可变参数模板

  24. 24

    可变参数模板类-可变参数成员函数

  25. 25

    g ++和clang具有递归可变参数模板位集创建的不同行为(可能是gcc错误?)

  26. 26

    可变参数模板的正确语法

  27. 27

    可变参数模板模板参数和GCC,Clang和MSVC中的sizeof差异-谁是正确的?

  28. 28

    可变参数模板参数和策略

  29. 29

    可变参数函数模板接受任何指针(指向变量,函数,成员函数等)作为参数

热门标签

归档