Clang 和 Gcc 不同意实例化后的显式特化
Clang and Gcc disagree on explicit specialization after instantiation
在某些代码中,我正在审查 运行 Clang 和 Gcc 不同意的情况。环顾四周后,我似乎无法弄清楚谁是对的。
免责声明:我知道有更好的单例模式,但这是代码中使用的模式。
备注:
gcc 7.4.0 on Ubuntu(无错误)
clang 6.0.0 on Ubuntu(抛出错误)
所有 post 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
来自这个回答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()
{
}
这两个编译器在技术上都没有错。代码无效,但 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;
在某些代码中,我正在审查 运行 Clang 和 Gcc 不同意的情况。环顾四周后,我似乎无法弄清楚谁是对的。
免责声明:我知道有更好的单例模式,但这是代码中使用的模式。
备注:
gcc 7.4.0 on Ubuntu(无错误)
clang 6.0.0 on Ubuntu(抛出错误)
所有 post 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
来自这个回答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()
{
}
这两个编译器在技术上都没有错。代码无效,但 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;