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

时间:2016-07-17 11:22:15

标签: c++ templates c++11 tuples variadic-templates

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

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

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

请注意???实例中的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;
}

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

2 个答案:

答案 0 :(得分:3)

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

#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;
}

答案 1 :(得分:2)

假设您已经写过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;
}