给定 std::tuple<T...> 时可变参数模板类的实例化?

Instantiation of a variadic template class when given an std::tuple<T...>?

本文关键字:参数 实例化 变参 tuple std lt 给定 gt      更新时间:2023-10-16

我正在尝试编写一个处理程序类,当给定元组时,它可以动态处理给定元组中的特定字段。

问题是,我不知道如何创建该类的实例,因为该类是模板化的,而我实例化所需的模板在元组内。

(由于与问题无关的设计请求,将处理程序放在单独的类中很重要)

请注意ILevelHandler实例中的???,我需要提供模板,但不确定该怎么做。

#include <tuple>
#include <string>
#include <iostream>
#include <boost/variant.hpp>
template <typename... T>
class ILevelHandler
{
public:
    virtual void HandleEnterLevel(const boost::variant<T...>& _value)
    {
        std::cout << " value: " << _value << std::endl;
    }   
};
int main()
{
    std::tuple<int, float, std::string, int> tpl {4, 6.6, "hello", 7};
    ILevelHandler<???> lvl(tpl);
    for (size_t i = 0; i < 4; ++ i)
    {
        lvl.HandleEnterLevel(i, dynamic_get(i, tpl));
    }
    return 0;
}

值得一提的是:使用未包装在类中的函数解决问题很容易,尽管我需要提供一个抽象类,以便用户必须自己实现该函数。

作为一种可能的解决方案,您可以使用支持假函数,如下所示:

#include <tuple>
#include <string>
template <typename... T>
class ILevelHandler {
public:
    ILevelHandler(const std::tuple<T...> &) {}
};
template<typename... T>
auto f(const std::tuple<T...> &) -> ILevelHandler<T...>;
int main() {
    std::tuple<int, float, std::string, int> tpl {4, 6.6, "hello", 7};
    decltype(f(tpl)) lvl(tpl);
    return 0;
}

请注意,您不需要定义函数f,像上面示例中的简单声明就足够了。
您还可以使用几个using声明来清理一些语句:

// ...
template<typename T>
using MyILevelHandler = decltype(f(std::declval<T>()));
// ...
int main() {
    using MyTuple = std::tuple<int, float, std::string, int>;
    MyTuple tpl {4, 6.6, "hello", 7};
    MyILevelHandler<MyTuple> lvl(tpl);
    return 0;
}

假设你已经写了dynamic_get(比如如果你需要帮助),那么一个简单的转换类应该可以做到这一点:

#include <tuple>
#include <string>
#include <iostream>
#include <boost/variant.hpp>
template <typename... T>
class ILevelHandler
{
public:
    void HandleEnterLevel(const boost::variant<T...>& _value)
    {
        std::cout << " value: " << _value << std::endl;
    }
};
template<class Thing>
struct to_variant;
template<class...T>
struct to_variant<std::tuple<T...>>
{
    using type = boost::variant<T...>;
};
template<class T> using to_variant_t = typename to_variant<T>::type;

int main()
{
    std::tuple<int, float, std::string, int> tpl {4, 6.6, "hello", 7};
    using tuple_type = decltype(tpl);
    using variant_type = to_variant_t<tuple_type>;
    ILevelHandler< variant_type > lvl;
    for (size_t i = 0; i < 4; ++ i)
    {
        lvl.HandleEnterLevel(i, dynamic_get(i, tpl));
    }
    return 0;
}