I defined three variadic template functions in class as static methods. Than I decided to move them to namespace. Namespace-approach fails to compile while class-solution compiles and works as expected.
Here is working class - based solution:
#include <list>
#include <string>
class sample
{
public:
template<typename T>
static std::string encode(T t) {
/* do something useful with t */
return std::string("encoded value");
}
template<typename... Ts>
static std::string encode(Ts... ts) {
std::list<std::string> values;
return encode(values, ts...);
}
template<typename T, typename... Ts>
static std::string encode(std::list<std::string>& values, T t, Ts... ts) {
values.push_back(encode(t));
return encode(values, ts...);
}
};
Here are similar definitions within namespace:
#include <list>
#include <string>
namespace sample
{
template<typename T>
std::string encode(T t) {
/* do something useful with t */
return std::string("encoded value");
}
template<typename... Ts>
std::string encode(Ts... ts) {
std::list<std::string> values;
return encode(values, ts...);
}
template<typename T, typename... Ts>
std::string encode(std::list<std::string>& values, T t, Ts... ts) {
values.push_back(encode(t));
return encode(values, ts...);
}
};
In both cases encode is used in the following way:
std::string encoded = sample::encode(1, 2u, 3.0);
Namespace-approach fails with following error (first line shortened):
sample_namespace.hpp: In instantiation of ‘std::__cxx11::string sample::encode(Ts ...) [with Ts = {std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, ...
sample_namespace.hpp:18:22: recursively required from ‘std::__cxx11::string sample::encode(Ts ...) [with Ts = {std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, int, unsigned int, double}]’
sample_namespace.hpp:18:22: required from ‘std::__cxx11::string sample::encode(Ts ...) [with Ts = {int, unsigned int, double}]’
sample_namespace.hpp:17:32: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
std::list<std::string> values;
^~~~~~
compilation terminated.
The same error occurs when encode(int, uint, double) is defined explicitly:
template std::string sample::encode<int, uint, double>(int a, uint b, double c);
When single argument is given first template is encode(T t) used and code compiles.
Why templates placed within namespace fails?
Above code was (not)compiled with gcc 6.4.0 x86_64. I also tried to compile it with C++14 and C++17 enabled.
Code fails to compile with gcc 7.3, clang 6.0.0 and icc 18 too - checked via godbolt.org .
Just need to move the variadic template
form of encode
before the non-variadic template
form. When you're dealing with non-member functions, the order matters much more than it does for member functions. Godbolt accepts the following:
#include <list>
#include <string>
namespace sample
{
template<typename T>
std::string encode(T t) {
/* do something useful with t */
return std::string("encoded value");
}
template<typename T, typename... Ts>
std::string encode(std::list<std::string>& values, T t, Ts... ts) {
values.push_back(encode(t));
return encode(values, ts...);
}
template<typename... Ts>
std::string encode(Ts... ts) {
std::list<std::string> values;
return encode(values, ts...);
}
};
std::string do_it() {
return sample::encode(1, 2u, 3.0);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.