Clang 和 Gcc 不同意实例化后的显式特化

Clang and Gcc disagree on explicit specialization after instantiation

在某些代码中,我正在审查 运行 Clang 和 Gcc 不同意的情况。环顾四周后,我似乎无法弄清楚谁是对的。

免责声明:我知道有更好的单例模式,但这是代码中使用的模式。

备注:

foo.hh

#include "sing.hh"

class Foo {
    public: 
    Foo();
    ~Foo();
    static Foo *getSingleton(){
        return singleton<Foo>::instance();  
    }
};

foo.cc

include "foo.hh"
//removing this line results in the error for clang disappearing 
template<> singleton<Foo>::GetInstance singleton<Foo>::instance = nullptr; 
int main(){};

sing.hh

template<typename T>
class singleton{
    typedef T *(*GetInstance)(void);
public:

  static GetInstance instance;

};

结果:

$ clang++  foo.cc
foo.cc:3:56: error: explicit specialization of 'instance' after instantiation
template<> singleton<Foo>::GetInstance singleton<Foo>::instance = nullptr;
                                                       ^
./foo.hh:10:32: note: implicit instantiation first required here
        return singleton<Foo>::instance();  
                               ^
1 error generated.



$ g++  foo.cc <- No Errors

来自这个回答here and the cpp-reference here

Explicit specialization may be declared in any scope where its primary template may be defined [...].

Explicit specialization has to appear after the non-specialized template declaration.

Specialization must be declared before the first use that would cause implicit instantiation, in every translation unit where such use occurs

如果显式特化在 sing.cpp 文件中,那么两个编译器都不会抱怨。或者,您可以使用前向声明来执行以下操作,clang 和 gcc 都会很高兴。

#include <iostream>

template<typename T>
struct singleton
{
    typedef T *(*GetInstance)(void);

    static GetInstance instance;
};

template<>
singleton<struct Foo>::GetInstance singleton<struct Foo>::instance = nullptr;

struct Foo
{
    static Foo *getSingleton()
    {
        return singleton<Foo>::instance();  
    }
};

int main()
{

}

在线代码示例:https://rextester.com/SPZLS83155

这两个编译器在技术上都没有错。代码无效,但 C++ 实现不需要提供有关此类错误的诊断消息。

标准 [temp.expl.spec]/6 说(强调我的):

If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.

您可以通过在 sing.hh 中的 singleton 定义之后立即声明显式特化来解决此问题:

struct Foo;
template<> singleton<Foo>::GetInstance singleton<Foo>::instance;

或者,如果您希望所有特化都初始化为空指针,您可以只定义通用 class 模板的成员,同样可能在 sing.hh 中。然后就不需要显式特化,除非你想为某些特定类型使用不同的初始化器。

template<typename T>
typename singleton<T>::GetInstance singleton<T>::instance = nullptr;