在使用 Clang 编译 CRTP Singleton 时,如何解决据称缺少 "explicit instantiation declaration" 的问题?
How to fix a purported lack of an "explicit instantiation declaration" when compiling a CRTP Singleton with Clang?
我们正在使用 curiously recurring template pattern 来实现单例。但是,在最近的 Clang 版本中,我们收到了 -Wundefined-var-template 警告。建议的修复方法是添加 "explicit instantiation declaration"。
我试图这样做,但后来我在定义单例模板 class 成员变量的编译单元中得到关于 "explicit specialization after instantiation" 的错误。
解决此警告突出显示的问题的适当结构是什么?
简化 详细信息(已删除大部分逻辑,以制作 MCVE):
SingletonBase.hh:
template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};
Singleton.hh:
#include "SingletonBase.hh"
class Singleton : public SingletonBase< Singleton > {
friend class SingletonBase< Singleton >;
public:
int do_stuff(int v) { return v+2; }
private:
static Singleton * create_singleton_instance() {
return new Singleton;
}
};
Singleton.cc:
#include "Singleton.hh"
template <> Singleton * SingletonBase< Singleton >::instance_( nullptr );
当我们使用最新版本的 clang(3.9.0;但不是 clang 3.7)进行编译时,我们在编译 Singleton.cc 以外的文件时会收到警告。 (使用 -std=c++11 和 -Werror)
In file included from OtherFile.cc:2:
In file included from ./Singleton.hh:2:
./SingletonBase.hh:5:16: warning: instantiation of variable 'SingletonBase<Singleton>::instance_' required here, but no definition is available [-Wundefined-var-template]
if ( ! instance_ ) {
^
OtherFile.cc:5:25: note: in instantiation of member function 'SingletonBase<Singleton>::get_instance' requested here
return Singleton::get_instance()->do_stuff(4);
^
./SingletonBase.hh:11:18: note: forward declaration of template entity is here
static T * instance_;
^
./SingletonBase.hh:5:16: note: add an explicit instantiation declaration to suppress this warning if 'SingletonBase<Singleton>::instance_' is explicitly instantiated in another translation unit
if ( ! instance_ ) {
^
1 error generated.
我在 Singleton.hh 的末尾添加了以下行,因为我 lead to believe 显式实例化声明语法应该是这样的。
extern template Singleton* SingletonBase< class Singleton >::instance_;
虽然这修复了编译 OtherFile.cc 的问题,但在编译 Singleton.cc
时会导致新的错误
Singleton.cc:3:57: error: explicit specialization of 'instance_' after instantiation
template <> Singleton * SingletonBase< Singleton >::instance_( nullptr );
^
./Singleton.hh:14:66: note: explicit instantiation first required here
extern template Singleton* SingletonBase< class Singleton >::instance_;
^
1 error generated.
我应该在这里做什么来修复这些 warnings/errors?对于我不理解的显式实例化声明,是否有更合适的语法?
我建议改为使用这种单例实现:
template<class T>
struct SingletonBase {
static T& get_instance() {
static T instance;
return instance;
}
};
它是线程安全的,移除你的警告。
如果你愿意,你可以保留你的 create_singleton_instance
:
template<class T>
struct SingletonBase {
static T& get_instance() {
static T instance{T::create_singleton_instance()};
return instance;
}
};
并将函数实现更改为:
static SomeClass create_singleton_instance() {
return {};
}
最简单的解决方法是在 SingletonBase.hh 中定义 instance_
:
template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};
template <typename T>
T* SingletonBase<T>::instance_ = nullptr;
但是,如果您要依赖 T::create_singleton_instance()
来创建实例,我不明白 SingletonBase
的意义。您不妨在派生的 class.
中实现 get_instance()
只有当基础 class 可以使用默认构造函数构造派生 class 的实例时,使用 CRTP 实现单例模式才有意义。
template < class T > class SingletonBase {
public:
static T& get_instance() {
static T instance_;
return instance_;
}
private:
};
进一步阅读:How to implement multithread safe singleton in C++11 without using <mutex>
显然,显式实例化声明的形式应该是
template <> Singleton * SingletonBase< Singleton >::instance_;
我们正在使用 curiously recurring template pattern 来实现单例。但是,在最近的 Clang 版本中,我们收到了 -Wundefined-var-template 警告。建议的修复方法是添加 "explicit instantiation declaration"。
我试图这样做,但后来我在定义单例模板 class 成员变量的编译单元中得到关于 "explicit specialization after instantiation" 的错误。
解决此警告突出显示的问题的适当结构是什么?
简化 详细信息(已删除大部分逻辑,以制作 MCVE):
SingletonBase.hh:
template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};
Singleton.hh:
#include "SingletonBase.hh"
class Singleton : public SingletonBase< Singleton > {
friend class SingletonBase< Singleton >;
public:
int do_stuff(int v) { return v+2; }
private:
static Singleton * create_singleton_instance() {
return new Singleton;
}
};
Singleton.cc:
#include "Singleton.hh"
template <> Singleton * SingletonBase< Singleton >::instance_( nullptr );
当我们使用最新版本的 clang(3.9.0;但不是 clang 3.7)进行编译时,我们在编译 Singleton.cc 以外的文件时会收到警告。 (使用 -std=c++11 和 -Werror)
In file included from OtherFile.cc:2:
In file included from ./Singleton.hh:2:
./SingletonBase.hh:5:16: warning: instantiation of variable 'SingletonBase<Singleton>::instance_' required here, but no definition is available [-Wundefined-var-template]
if ( ! instance_ ) {
^
OtherFile.cc:5:25: note: in instantiation of member function 'SingletonBase<Singleton>::get_instance' requested here
return Singleton::get_instance()->do_stuff(4);
^
./SingletonBase.hh:11:18: note: forward declaration of template entity is here
static T * instance_;
^
./SingletonBase.hh:5:16: note: add an explicit instantiation declaration to suppress this warning if 'SingletonBase<Singleton>::instance_' is explicitly instantiated in another translation unit
if ( ! instance_ ) {
^
1 error generated.
我在 Singleton.hh 的末尾添加了以下行,因为我 lead to believe 显式实例化声明语法应该是这样的。
extern template Singleton* SingletonBase< class Singleton >::instance_;
虽然这修复了编译 OtherFile.cc 的问题,但在编译 Singleton.cc
时会导致新的错误Singleton.cc:3:57: error: explicit specialization of 'instance_' after instantiation
template <> Singleton * SingletonBase< Singleton >::instance_( nullptr );
^
./Singleton.hh:14:66: note: explicit instantiation first required here
extern template Singleton* SingletonBase< class Singleton >::instance_;
^
1 error generated.
我应该在这里做什么来修复这些 warnings/errors?对于我不理解的显式实例化声明,是否有更合适的语法?
我建议改为使用这种单例实现:
template<class T>
struct SingletonBase {
static T& get_instance() {
static T instance;
return instance;
}
};
它是线程安全的,移除你的警告。
如果你愿意,你可以保留你的 create_singleton_instance
:
template<class T>
struct SingletonBase {
static T& get_instance() {
static T instance{T::create_singleton_instance()};
return instance;
}
};
并将函数实现更改为:
static SomeClass create_singleton_instance() {
return {};
}
最简单的解决方法是在 SingletonBase.hh 中定义 instance_
:
template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};
template <typename T>
T* SingletonBase<T>::instance_ = nullptr;
但是,如果您要依赖 T::create_singleton_instance()
来创建实例,我不明白 SingletonBase
的意义。您不妨在派生的 class.
get_instance()
只有当基础 class 可以使用默认构造函数构造派生 class 的实例时,使用 CRTP 实现单例模式才有意义。
template < class T > class SingletonBase {
public:
static T& get_instance() {
static T instance_;
return instance_;
}
private:
};
进一步阅读:How to implement multithread safe singleton in C++11 without using <mutex>
显然,显式实例化声明的形式应该是
template <> Singleton * SingletonBase< Singleton >::instance_;