如何从参数包中定义值类型的元组

How to define a tuple of value types from a parameter pack

我需要构建一个 n 类型的元组。这 n 个类型是 n 个其他类型的值类型。考虑这个片段:

#include <boost/hana.hpp>

namespace hana = boost::hana;

template<class... Types>
class CartesianProduct
{
public:
    CartesianProduct(Types... args) : sets(args...) {}

    hana::tuple<Types...> sets;
    hana::tuple<Types...::value_type> combination; // does not work obviously... but wo can this be done?
};

这个应用的目的是这样的:我传递这个class一个可能不同类型的容器的参数包。 class 将这些容器放入元组 sets 中。 class 也有一个字段 combination,它是一个元组,包含与传递给 class 的容器一样多的元素。但是元素的类型是不同容器的值类型。

然后 class 用于懒惰地构建传递给它的容器的笛卡尔积,并将当前组合存储在 combination 中。但是我怎样才能真正以可变参数的方式获取容器的值类型呢?

当然可以。您只需要适当地声明包扩展。

hane::tuple<typename Types::value_type...> combination; 

注意需要使用类型名称说明符。经验法则是将包名称视为单一类型。相同的 syntactic/semantic 约束适用,因为我们必须指定我们使用范围解析运算符访问类型。然后在最后添加扩展包。

Live Example

#include <vector>
#include <map>
#include <tuple>

template<class... Types>
class CartesianProduct
{
public:
    CartesianProduct(Types... args) : sets(args...) {}

    std::tuple<Types...> sets;
    std::tuple<typename Types::value_type...> combination; 
};


int main() {
    std::vector<int> i;
    std::map<int, std::vector<int>> m;

    CartesianProduct<std::vector<int>, std::map<int, std::vector<int>>>
      c(i, m);

    return 0;
}

扩展 StoryTeller 的正确答案(请采纳他的答案):

我发现通过根据翻译元函数来实现这样的类型翻译更容易可视化,例如:

#include <vector>
#include <map>
#include <tuple>

namespace metafunction_impl
{
  // meta function taking one type (T) and 'returning' one type.
  // i.e. a unary metafunction
  template<class T> struct get_value_type
  {
    using result = typename T::value_type;
  };
}

// provide clean interface to the metafunction
template<class T> using GetValueType = typename metafunction_impl::get_value_type<T>::result;

template<class... Types>
class CartesianProduct
{
public:
    CartesianProduct(Types... args) : sets(args...) {}

    std::tuple<Types...> sets;

    // use my metafunction
    std::tuple<GetValueType<Types>...> combination; 
};


int main() {
    std::vector<int> i;
    std::map<int, std::vector<int>> m;

    CartesianProduct<std::vector<int>, std::map<int, std::vector<int>>>
      c(i, m);

    return 0;
}