将成员元组传递给非成员结构而不在模板中指定它

时间:2016-02-25 12:29:37

标签: c++ templates c++11 c++14

为了避免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");
}

1 个答案:

答案 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...>{});
}

Live Demo