我有这样的test.hpp
:
#include <cstring>
#include <cassert>
#include <map>
template <typename T, typename Tag>
struct Boo {
using ElementType = T;
static const char name[];
};
struct CFG_ELM_NAME__Pref1 {};
using Pref1 = Boo<int, CFG_ELM_NAME__Pref1>;
struct Foo {
template <typename CfgElm>
void get() const {
auto it = cache_.find(CfgElm::name);
assert(it != cache_.end());
}
Foo();
private:
struct CmpCStr final {
bool operator()(const char *a, const char *b) const {
return std::strcmp(a, b) < 0;
}
};
using PrefCacheMap = std::map<const char *, int, CmpCStr>;
PrefCacheMap cache_;
};
并像这样使用它(test2.cpp
):
#include "test.hpp"
void f()
{
Foo foo;
foo.get<Pref1>();
}
并像这样初始化它(test.cpp
):
#include "test.hpp"
template <> const char Pref1::name[] = "Pref1";
Foo::Foo()
{
cache_.insert(std::make_pair(Pref1::name, 17));
}
这是简化的例子,所以 Foo::get
什么都不做。
clang 对此代码产生这样的警告:
clang++ -Wall -Wextra -std=c++11 test.cpp test2.cpp
In file included from test2.cpp:1:
./test.hpp:15:35: warning: instantiation of variable 'Boo<int,
CFG_ELM_NAME__Pref1>::name' required here, but no definition is
available [-Wundefined-var-template]
auto it = cache_.find(CfgElm::name);
^
test2.cpp:6:6: note: in instantiation of function template specialization
'Foo::get<Boo<int, CFG_ELM_NAME__Pref1> >' requested here
foo.get<Pref1>();
^
./test.hpp:7:21: note: forward declaration of template entity is here
static const char name[];
^
./test.hpp:15:35: note: add an explicit instantiation declaration to
suppress this warning if 'Boo<int, CFG_ELM_NAME__Pref1>::name' is
explicitly instantiated in another translation unit
auto it = cache_.find(CfgElm::name);
这段代码编译和链接没有问题。 唯一的问题是警告。 我不知道如何抑制它。
我发现了这个问题 explicit instantiation of static variable of a template class in different translation units , 但我不能使用提供的解决方案,因为我不知道模板参数。
我不能写:template<> int Boo<Type1, Type2>::name;
因为整个想法是像这样使用我的代码:foo.get<Pref1>()
, 没有明确指出 Pref1
是Boo<int, CFG_ELM_NAME__Pref1>
.
所以任何人都知道如何抑制警告,而无需通过 -Wno-undefined-var-template
对整个项目发出此类警告?
最佳答案
您应该在同一头文件中添加 Boo::name
模板定义:
static const char * name;
}; // End Boo
template<typename T, typename Tag>
const char * Boo<T, Tag>::name{};
更新:现在已明确您正尝试在头文件中实例化 后的某个翻译单元中为 name
编写特化。这将需要一些技巧。您需要在实例化它之前在头文件中声明特化,并且可能使用外部模板并在与 name
相同的翻译单元中显式实例化它:
// header
template <typename T, typename Tag> struct Boo {
using ElementType = T;
static const char * name;
};
struct CFG_ELM_NAME__Pref1 {};
// indicate that name for this specialization exists elsewhere
template<> const char * Boo<int, CFG_ELM_NAME__Pref1>::name;
// indicate that template is defined somewhere
extern template struct Boo<int, CFG_ELM_NAME__Pref1>;
using Pref1 = Boo<int, CFG_ELM_NAME__Pref1>;
// test.cpp
// definition will be present only in this translation unit
template<> const char * Boo<int, CFG_ELM_NAME__Pref1>::name{"Pref1"};
// explicit instantiation
template struct Boo<int, CFG_ELM_NAME__Pref1>;
关于c++ - 模板类字段的显式实例化声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48451591/