从构造函数参数的组合生成变量类型的对象

Ios*_*ber 12 c++ variadic-functions c++11

假设我有类型A,B有构造函数A(int a, double b, std::string c),B(double a, int b).

我知道如何定义一个实例化AB通过可变参数模板的函数.

有没有办法设计一个函数/宏/类型,对于一个类型T和一系列T构造函数参数的可能性向量,它为我提供了所有可能的对象?

例如,如果我使用这个神奇的构造,<A, {2, 5, 6}, {2.44, 3.14}, {"yes", "no"}>它应该提供对象:

A(2, 2.44, "yes")
A(2, 2.44, "no")
A(2, 3.14, "yes")
...
A(6, 3.14, "no")
Run Code Online (Sandbox Code Playgroud)

这同样适用于B任何其他类型,而不必重新设计魔法结构.

例如,这在Python中非常简单,但我不知道它是否可以在C++中使用.

Yak*_*ont 6

std::experimental::array_view用于提高效率.您可以std::vector以某些运行时成本替换它,或以一定的清晰度成本替换一对迭代器/指针.

template<class T>
using array_view = std::experimental::array_view<T>;

using indexes = array_view<std::size_t>;
Run Code Online (Sandbox Code Playgroud)

这会迭代每个元素的交叉积,<索引中的相应索引.因此,{3,3,2}is在迭代{0,0,0}然后{0,0,1}一路{2,2,1}.

template<class F>
void for_each_cartesian_product(
  indexes is,
  F&& f,
  std::vector<std::size_t>& result
) {
  if (is.empty()) {
    f(result);
    return;
  }
  auto max_index = is.front();
  for (std::size_t i = 0; i < max_index; ++i) {
    result.push_back(i);
    for_each_cartesian_product( {is.begin()+1, is.end()}, f, result );
    result.pop_back();
  }
}
template<class F>
void for_each_cartesian_product(
  indexes is,
  F&& f
) {
  std::vector<size_t> buffer;
  for_each_cartesian_product( is, f, buffer );
}
Run Code Online (Sandbox Code Playgroud)

然后我们只填充我们的索引:

template<class...Ts>
std::vector<std::size_t> get_indexes( std::vector<Ts> const&... vs ) {
  return {vs.size()...};
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们可以只需要接受我们的参数,将它们放在一个向量中,然后使用索引从每个向量中获取元素并将它们传递A给构造.

template<class T, std::size_t...Is, class...Args>
std::vector<T> make_stuff( std::index_sequence<Is...>, std::vector<Args>const&... args ) {
  std::vector<T> retval;
  for_each_cartesian_product(
    get_indexes(args...),
    [&](auto&& index){
      retval.emplace_back( args[ index[Is] ]... );
    }
  );
  return retval;
}
template<class T, class...Args>
std::vector<T> make_stuff( std::vector<Args>const&... args ) {
  return make_stuff<T>( std::index_sequence_for<Args...>{}, args... );
}
Run Code Online (Sandbox Code Playgroud)

和鲍勃是你的叔叔.

A生成的s可以移动.

在编译时使用编译时已知数组执行此操作也可以完成.

index_sequence_for并且index_sequence是C++ 14,但很容易在C++ 11中实现.堆栈溢出有很多例子.

上面的代码尚未编译.