在某些代码中,我正在审查我遇到Clang和Gcc意见不同的情况。环顾了一会后,我似乎无法弄清楚谁是对的。
免责声明 :我知道有一个更好的Singleton模式,但这是代码中使用的模式。
注释:
在Ubuntu上的gcc 7.4.0(无错误)
clang 6.0.0(抛出错误)
对于所有C ++ 11后的ISO版本似乎都存在差异,但是我没有更早尝试过。
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
答案 0 :(得分:2)
两个编译器在技术上都不是错误的。该代码无效,但是不需要C ++实现来提供有关此类错误的诊断消息。
标准[temp.expl.spec]/6说(强调我):
如果一个模板,一个成员模板或一个类模板的成员是显式专门化的,则应在首次使用该专门化之前声明该专门化,这将导致在每个此类翻译单元中进行隐式实例化发生使用; 不需要诊断。
您可以通过在sing.hh中定义singleton
之后立即声明显式专门化来解决此问题:
struct Foo;
template<> singleton<Foo>::GetInstance singleton<Foo>::instance;
或者,如果您希望所有专业化都初始化为空指针,则可以只在sing.hh中定义通用类模板的成员。则不需要显式的专业化,除非您希望某些特定类型使用不同的初始化器。
template<typename T>
typename singleton<T>::GetInstance singleton<T>::instance = nullptr;
答案 1 :(得分:0)
显式专业化可以在任何主要专业化范围内声明 可以定义模板。[...]
显式专业化必须出现在非专业化之后 模板声明。
必须在第一次使用之前声明专业化 隐式实例化,在每个这样使用的翻译单元中 发生
如果显式专业化位于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()
{
}