假设我有类型A
,B
有构造函数A(int a, double b, std::string c)
,B(double a, int b)
。
我知道如何定义一个实例化A
或B
通过可变参数模板实例化的函数。
有没有什么方法可以设计一个函数/宏/类型,以便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")
相同的东西应该适用于B
任何其他类型,而不必重新构造神奇的构造。
例如,这在Python中超级简单,但我不知道在C ++中是否可行。
这std::experimental::array_view
用于提高效率。您可以std::vector
花费一些运行时成本来替换它,或者以一些清晰的代价来替换一对迭代器/指针。
template<class T>
using array_view = std::experimental::array_view<T>;
using indexes = array_view<std::size_t>;
这将遍历每个元素的叉积,<
分别对应索引中的索引。所以{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 );
}
然后我们就填充索引:
template<class...Ts>
std::vector<std::size_t> get_indexes( std::vector<Ts> const&... vs ) {
return {vs.size()...};
}
接下来,我们只需要接受参数,将其放入向量中,然后使用索引从每个向量中获取元素并将它们传递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... );
}
鲍勃是你叔叔
该A
生成的S可以被移动。
也可以在编译时使用已知的数组执行此操作。
index_sequence_for
和index_sequence
是C ++ 14,但易于在C ++ 11中实现。堆栈溢出有很多例子。
上面的代码尚未编译。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句