TMP: ¿cómo generalizar un producto cartesiano de vectores?

Existe una excelente solución de C ++ (en realidad, 2 soluciones: recursiva y no recursiva), en un producto cartesiano de un vector de vectores enteros . Para fines de ilustración / simplicidad, centrémonos en la versión no recursiva .

Mi pregunta es, ¿cómo se puede generalizar este código con plantillas para tomar una std::tuple de vectores homogéneos que se ve así:

{{2,5,9},{"foo","bar"}}

y generar un vector homogéneo de tuple

{{2,"foo"},{2,"bar"},{5,"foo"},{5,"bar"},{9,"foo"},{9,"bar"}}

Si hace la vida más fácil, supongamos que los vectores internos en la entrada son homogéneos. Por lo tanto, no se permiten entradas como esta: {{5,"baz"}{'c',-2}}

EDIT cambió la entrada del vector irregular a una tupla

    Solución recursiva más simple. Toma vectores como argumentos de función, no como una tupla. Esta versión no construye tuplas temporales, sino que usa lambdas en su lugar. Ahora no hace copias / movimientos innecesarios y parece optimizarse con éxito.

     #include #include // cross_imp(f, v...) means "do `f` for each element of cartesian product of v..." template inline void cross_imp(F f) { f(); } template inline void cross_imp(F f, std::vector const& h, std::vector const&... t) { for(H const& he: h) cross_imp([&](Ts const&... ts){ f(he, ts...); }, t...); } template std::vector> cross(std::vector const&... in) { std::vector> res; cross_imp([&](Ts const&... ts){ res.emplace_back(ts...); }, in...); return res; } #include int main() { std::vector is = {2,5,9}; std::vector cps = {"foo","bar"}; std::vector ds = {1.5, 3.14, 2.71}; auto res = cross(is, cps, ds); for(auto& a: res) { std::cout < < '{' << std::get<0>(a) < < ',' << std::get<1>(a) < < ',' << std::get<2>(a) < < "}\n"; } } 

    Ha pasado un tiempo desde que he estado haciendo esto, pero aquí hay un primer bash. Sin duda se puede mejorar.

     template class DynamicTupleGetter { typedef typename std::tuple_element::type RetType; public: static RetType get(unsigned dynIndex, const T& tupleInstance) { const RetType& ret = std::get(tupleInstance); if (fixedIndex == dynIndex) return ret; return DynamicTupleGetter::get(dynIndex, tupleInstance); } }; template class DynamicTupleGetter<0, T> { typedef typename std::tuple_element<0, T>::type RetType; public: static RetType get(unsigned dynIndex, const T& tupleInstance) { assert(dynIndex == 0); return std::get<0>(tupleInstance); } }; template struct Converter { typedef typename std::tuple_element<0, Source>::type Zeroth; typedef typename std::tuple_element<1, Source>::type First; static const size_t size0 = std::tuple_size::value; static const size_t size1 = std::tuple_size::value; static const size_t outerProductSize = size0 * size1; typedef typename std::tuple_element<0, Zeroth>::type BaseType0; typedef typename std::tuple_element<0, First>::type BaseType1; typedef typename std::tuple EntryType; typedef std::array DestinationType; DestinationType create(const Source& source) { Zeroth zeroth = std::get<0>(source); First first = std::get<1>(source); typedef typename DynamicTupleGetter ZerothGetter; typedef typename DynamicTupleGetter FirstGetter; DestinationType result; size_t resultIndex = 0; for(size_t i = 0; i < size0; ++i) for(size_t j = 0; j < size1; ++j) { std::get<0>(result[resultIndex]) = ZerothGetter::get(i, zeroth) ; std::get<1>(result[resultIndex]) = FirstGetter::get(j, first); ++resultIndex; } return result; } }; template void create(const T& source) { Converter converter; Converter::DestinationType result = converter.create(source); std::cout < < std::get<0>(std::get<3>(result)) < < "," << std::get<1>(std::get<3>(result)) < < std::endl; } auto intPart = std::make_tuple(2,5,9); auto stringPart = std::make_tuple("foo","bar"); auto source = std::make_tuple(intPart, stringPart); void f() { create(source); }