c ++模板奇怪的优化

Rio*_*pho 16 c++ gcc templates clang

我像boost一样写了一个单例模板类:

template <typename _T>
class Singleton
{ 
    public :
    static _T* Instance()
    {
        static _T obj;
        return &obj;
    }

protected :
    Singleton() {}

private :
    struct ObjectCreator
    {
        ObjectCreator()
        {
            Singleton<_T>::instance();
        }
    };

    static ObjectCreator object_creator;
};

template <typename _T>
typename Singleton<_T>::ObjectCreator Singleton<_T>::object_creator;
Run Code Online (Sandbox Code Playgroud)

我写了主要功能来测试它.

#include "Singleton.h"
class A : public Singleton <A>
{
    public:
        int a;
};


int main()
{
    A::Instance()->a = 2;
}
Run Code Online (Sandbox Code Playgroud)

我知道我错误地输入了Instance in ObjectCreator的构造函数,奇怪的是我可以通过gcc-4.4.7正确编译它,然后我使用了clang-6.0,它打了我的错字.

我猜gcc可以做一些优化,因为我没有做任何事情ObjectCreator,所以它忽略了错误代码.

我有两个问题:

  1. 我应该怎么做让gcc报告我错误(不改变我的代码),比如添加一些编译器标志?
  2. 如果有人对此有更可靠的解释?一些官方文件会这样做.

Ps:我知道boost会添加一个do_nothing函数ObjectCreate并调用它Singleton<_T>:: Instance()来避免这种优化.

use*_*999 6

  • 我应该怎么做才能让gcc报告错误(不改变我的代码),比如添加一些编译器标志?

你可以添加一个显式实例化template class Singleton<float>;(我只是随机选择float类型,但你可以选择更合适的东西)来强制GCC检查语法.有关示例,请参阅https://gcc.godbolt.org/z/ii43qX.

如果您只是想要检查,您还可以通过向项目添加另一个cpp文件将此显式实例放到单独的编译单元中.

然而,进行明确的实例化比隐式实例更强,因为所有成员和方法都将被实例化.此行为可能是有害的(请参阅示例的标准库).

  • 如果有人对此有更可靠的解释?一些官方文件会这样做.

静态成员不会被隐式初始化,直到它以需要定义的方式使用(这与显式实例非常不同).

@StoryTeller在标准中找到了正确的段落

14.7.1隐式实例化[temp.inst]

类模板特化的隐式实例化会导致类成员函数,成员类,静态数据成员和成员模板的声明的隐式实例化,而不是定义或默认参数的隐式实例化.它会导致成员匿名联合的定义的隐式实例化.除非已显式实例化或明确专门化类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化; 特别是,除非静态数据成员本身以需要静态数据成员的定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用).

编辑 您应该接受@StoryTeller的答案,因为他首先正确解释了您问题的两个方面.