如何从 std::tuple 获取可变参数以解压缩另一个 std::tuple?

How do I obtain the variadic arguments from an std::tuple to unpack for another std::tuple?

提问人:Kingsley Oyelabi 提问时间:10/11/2023 最后编辑:Ch3steRKingsley Oyelabi 更新时间:10/12/2023 访问量:123

问:

我正在尝试将模板参数列表(枚举类,而不是类型名称)转换为模板参数的相应类型名称,以转换为std::tuple。我猜如果我能以某种方式将可变参数列表命名为 ,我可能会在下一个模板递归中扩展它using type = ...

所以,我有枚举类:

enum class object_t{
    STR,
    INT,
    FLOAT,
};

模板应该提供具体的类(一些 std::tuple):

template <object_t _obj, object_t ...Args>
struct concrete {
        // here's the part I need to correct
    using type = std::tuple<typename concrete<_obj>::type, typename concrete<Args...>::type>;
};

尾随递归的专业化:

template <>
struct concrete<object_t::STR> {
    using type = std::string;
};

template <>
struct concrete<object_t::INT> {
    using type = int64_t;
};

template <>
struct concrete<object_t::FLOAT> {
    using type = double;
};

以及 ::type 速记的 using 声明

template<object_t _obj, object_t ...Args>
using concrete_t = typename concrete<_obj, Args...>::type;

最终,我想要类似的东西

concrete_t<object_t::INT, object_t::FLOAT, object_t::STR>

等同于

std::tuple<int64_t, double, std::string>

目前,这应该会产生类似的东西:

std::tuple<int64_t, std::tuple<double, std::string>>

相反。

我不是可变参数模板的最佳人选,但我在想,如果(通用模板的)使用类型是参数包而不是元组,我可能会为下一个元组解压缩它(然后我必须再次获取其参数列表,依此类推)。 像这样:

template <object_t _obj, object_t ...Args>
struct concrete {
    using type = std::tuple<typename concrete<_obj>::type, typename concrete<Args...>::type...>::elements_type;
};

其中 elements_type 是可变参数包,而 ::type...打开包装

但即使这样似乎也不对,因为根 ::type 将是一个参数包,而不是像 desired 那样的 std::tuple。也许需要另一个模板,我不知道。

任何建议都可能有很长的路要走,谢谢!

C++ 模板 variadic-templates 专项化

评论

2赞 Igor Tandetnik 10/11/2023
编写一个单独的模板,将枚举转换为类型,而不是执行双重任务。然后就写concretetemplate <object_t ...Args> struct concrete { using type = std::tuple<typename ObjectTraits<Args>::type...>; };
0赞 Igor Tandetnik 10/11/2023
实际上,目前尚不清楚:您想成为还是?使用您当前的方法,单参数实例化与多参数实例化不对称 - 您的意思是这样的吗?concrete_t<object_t::STR>std::stringstd::tuple<std::string>
0赞 Kingsley Oyelabi 10/11/2023
@IgorTandetnik谢谢你。我希望 concrete_t<object_t::STR> 是 std::tuple<std::string>,尽管我必须承认我事先没有注意到歧义。看来你的建议也解决了这个问题。谢谢!

答:

1赞 Kingsley Oyelabi 10/11/2023 #1

如果有人需要这个,多亏了@IgorTandetnik,解决方案看起来像这样:

enum class object_t{
    STR,
    INT,
    FLOAT,
};

template<object_t _obj>
struct concrete_traits;

template<>
struct concrete_traits<object_t::STR> {
    using type = std::string;
};

template<>
struct concrete_traits<object_t::INT> {
    using type = int64_t;
};

template<>
struct concrete_traits<object_t::FLOAT> {
    using type = double;
};

template <object_t ...Args> struct concrete {
    using type = std::tuple<typename concrete_traits<Args>::type...>;
};

template<object_t ...Args>
using concrete_t = typename concrete<Args...>::type;

这个答案是基于@IgorTandetnik评论。

为了消除单个模板参数的简单情况下的 std::tuple,专用化

template<object_t _obj>
struct concrete<_obj> {
    using type = typename concrete_traits<_obj>::type;
};

例如,使 be 代替 。concrete_t<object_t::STR>std::stringstd::tuple<std::string>

评论

0赞 Igor Tandetnik 10/11/2023
concrete_traits不需要是可变参数模板。来得及template<object_t Arg> struct concrete_traits;
0赞 Kingsley Oyelabi 10/12/2023
真。纠正了,谢谢。