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

passing member tuple to non-member struct without specifying it in template

本文关键字:成员 元组 结构      更新时间:2023-10-16

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

您可以避免递归并改用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...>{});
}

现场演示