I have such 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_;
};
and use it like this (test2.cpp):
#include "test.hpp"
void f()
{
Foo foo;
foo.get<Pref1>();
}
and initialize it like this (test.cpp):
#include "test.hpp"
template <> const char Pref1::name[] = "Pref1";
Foo::Foo()
{
cache_.insert(std::make_pair(Pref1::name, 17));
}
This is reduced example, so Foo::get do nothing.
clang produces such warning for this code:
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);
This codes does compiles and links without problems. The only problem is warning. I have no idea how to suppress it.
I found this question explicit instantiation of static variable of a template class in different translation units , but I can not use provided solution, because of I don't know template arguments.
I can not write: template<> int Boo<Type1, Type2>::name;
because of the whole idea is to use my code like this: foo.get<Pref1>(), without explicitly pointing that Pref1 is Boo<int, CFG_ELM_NAME__Pref1>.
So anybody know how to suppress warning, without turn of such warning for whole project via -Wno-undefined-var-template?
You should add Boo::name template definition in the same header file:
static const char * name;
}; // End Boo
template<typename T, typename Tag>
const char * Boo<T, Tag>::name{};
Update: now it is clarified that you are trying to write specialization for name in some translation unit after instantiating it in header file. This will require some trickery. You need to declare specialization in header file before instantiating it and probably use external template and explicitly instantiate it in the same translation unit as 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>;
online compiler
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With