为了避免XY问题,我有一个异构容器类,基本上是std::tuple
。我想让这个类能够接受访问者,将它们应用于元组的每个元素(不确定我是否静态应用它)。访问者的访问功能将被模板化,因此他们将能够完全使用某些类型的专业化。
问题:
当我想申请访问者时,我需要迭代一个容器,抓取有关访问者,元组和即将访问的元素索引的信息。但是当我想创建成员函数时,我发现我不能部分专门化它。这是我提出的解决方案,但我想以某种方式传递元组,而不指定在模板参数中包含元组的类型。
#pragma once
#include <tuple>
#include <functional>
template <typename Visitor, int N, typename ... DataTypes>
struct Extractor
{
static void applyVisitor(Visitor& v, std::tuple<DataTypes...>& t)
{
Extractor<Visitor, N - 1, DataTypes...>::applyVisitor(v, t);
v.visit(std::get<N>(t));
}
};
template <typename Visitor, typename ... DataTypes>
struct Extractor <Visitor, 0, DataTypes...>
{
static void applyVisitor(Visitor& v, std::tuple<DataTypes...>& t)
{
v.visit(std::get<0>(t));
}
};
template <typename ... DataTypes>
class MyTuple
{
std::tuple<DataTypes...> data;
public:
MyTuple(std::tuple<DataTypes...> data_) : data(data_) {}
template <typename Visitor>
void acceptVisitor(Visitor& v)
{
Extractor<Visitor, sizeof...(DataTypes) - 1, DataTypes...>::applyVisitor(v, data);
}
};
我正在考虑OOD,因此对类的数据进行操作的每个函数都应该是成员函数,但看起来C ++模板来自另一个世界。如果我做得不对,请提出另一种解决方案。
修改
正如评论中提到的那样,以下是访问者和客户呼叫acceptVisitor()
访问者
#pragma once
#include <iosfwd>
class Visitor
{
std::ostream& os;
public:
Visitor(std::ostream& outputStream) :os(outputStream) {}
template <typename T>
void visit(T& data)
{
std::cout << data << "\n";
}
};
主要
#include "HeteContainer.h"
#include "Visitor.h"
#include <iostream>
#include <string>
#include <cstdlib>
int main()
{
Visitor v(std::cout);
MyTuple<int, int, std::string> m({ 1, 1, "abc" });
m.acceptVisitor(v);
std::system("pause");
}
答案 0 :(得分:2)
您可以避免递归并改为使用std::index_sequence
:
template <typename Visitor, typename... DataTypes, std::size_t... Idx>
void applyVisitor(Visitor& v, std::tuple<DataTypes...>& t, std::index_sequence<Idx...>)
{
using expander=int[];
(void)expander{ (v.visit(std::get<Idx>(t)), 0)... };
}
然后您的acceptVisitor
函数变为:
template <typename Visitor>
void acceptVisitor(Visitor& v)
{
applyVisitor(v, data, std::index_sequence_for<DataTypes...>{});
}