传递的可变模板递归类型
Variadic template recursive types passing
我在这里找到了几乎令人满意的问题解决方案(第二个答案),但我不能在另一个编译单元中使用这种方式编写的代码,因为将代码放在头文件中会导致链接器抱怨多个函数定义,而只在头文件里放声明会导致链接程序未定义引用问题。
这是我的代码:
template <typename... types>
void foo();
template<>
void foo<>() {
return;
}
template<typename type, typename... types>
void foohelper() {
foo<types...>();
}
template <typename... types>
void foo() {
foohelper<types...>();
}
int main() {
foo<int, int>();
}
以下是我想要实现的目标:
class A {
public:
template<>
void foo<>() {
return;
}
template<typename parser, typename... parsers>
void foohelper() {
foo<parsers...>();
}
template <typename... parsers>
void foo() {
foohelper<parsers...>();
}
};
int main() {
A a;
a.foo<int, int>();
}
但这会在编译过程中导致以下错误:
explicit specialization 'void A::foo(void)' is not a specialization of a function template
有什么简单的解决方案吗?
不需要递归。这更简单:
#include <iostream>
#include <string>
#include <typeinfo>
class A {
public:
template<typename parser>
void foohelper() {
std::cout << "handled a " << typeid(parser).name() << std::endl;
// do work here
}
template <typename... parsers>
void foo() {
using expand = int[];
(void) expand { 0, (foohelper<parsers>(), 0)... };
}
};
int main() {
A a;
a.foo<int, int, double, std::string>();
}
样本输出:
handled a i
handled a i
handled a d
handled a NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
编辑:
为了响应不符合要求的微软编译器,这里有另一个不依赖于无大小数组的版本:
#include <iostream>
#include <string>
#include <typeinfo>
class A {
public:
template<typename parser>
void foohelper() {
std::cout << "handled a " << typeid(parser).name() << std::endl;
// do work here
}
template <typename... parsers>
void foo() {
// c++ strictly does not allow 0-sized arrays.
// so here we add a NOP just in case parsers is an empty type list
using expand = int[1 + sizeof...(parsers)];
(void) expand {
(foohelper<void>(), 0),
(foohelper<parsers>(), 0)...
};
}
};
// implement the NOP operation. Note specialisation is outside class definition.
template<> void
A::foohelper<void>() {}
int main() {
A a;
a.foo<int, int, double, std::string>();
a.foo<>();
}
编辑2:
带有前缀、后缀和语法分析器间调用的更完整的示例。写了这么多代码,你可能会开始想,"嘿!我可以在这里实现一个完整的领域特定语言!",你是对的。
然而,比这更复杂的事情可能会让你永远憎恨你的同事,所以我会避免走这条路。
#include <iostream>
#include <string>
#include <typeinfo>
class A {
public:
template<typename parser>
void foohelper() {
std::cout << "handled a " << typeid(parser).name();
// do work here
}
void prepare()
{
std::cout << "starting parsers: ";
}
void separator()
{
std::cout << ", ";
}
void nothing()
{
}
void done() {
std::cout << " done!" << std::endl;
}
template <typename... parsers>
void foo() {
// c++ strictly does not allow 0-sized arrays.
// so here we add a NOP just in case parsers is an empty type list
bool between = false;
using expand = int[2 + sizeof...(parsers)];
(void) expand {
(prepare(), 0),
((between ? separator() : nothing()), between = true, foohelper<parsers>(), 0)...,
(done(), 0)
};
}
};
int main() {
A a;
a.foo<int, int, double, std::string>();
a.foo<>();
}
样本输出:
starting parsers: handled a i, handled a i, handled a d, handled a NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE done!
starting parsers: done!
相关文章:
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 从类型列表中递归删除重复项会导致编译器堆空间错误 (VS2017)
- 此递归模板类型定义是否有效C++?
- 递归函数的返回类型推导
- 在迭代模板类型列表时无法停止递归
- 如何使用common_type和模板递归类型重载运算符+
- C++ 相互递归的变体类型(再次)
- C++ 引用类型作为递归函数参数
- 我的编辑距离递归代码中的字符类型有问题
- 区分递归类型的结合
- 具有类型名的模板的递归实例化
- C 递归类型定义
- C++递归类型特征
- C++ std::函数,返回它自己的类型(再次递归类型)
- 递归类型真的是构建不连续的任意大小数据结构的唯一方法吗
- 使用模板进行递归类型检查
- 传递的可变模板递归类型
- 使用模板进行递归类型上转换
- 是否可以C++递归类型定义,特别是我可以在 T 的定义中放置一个向量<T>吗?
- decltype,重载运算符的递归类型推导