vendredi 27 mars 2015

Reordering an argument pack so that std::tie can operate on it, given a tuple

Given std::tuple<Ts...> tuple and a pack of types Types... types, we want to carry out std::tie(_types...) = tuple, where _types... is obtained from types... by reordering it so that std::tie(_types...) = tuple; will make sense (std::ignore shall be inserted in _types... if no type in types... is found to match any in Ts...). I'm calling this function



template <typename... Ts, typename... Types>
std::tuple<Ts...> tiePackToTuple (const std::tuple<Ts...>& tuple, Types&... types)


Here's what I have so far.



#include <iostream>
#include <tuple>
#define show(variable) std::cout << #variable << " = " << variable << std::endl;

template <class T>
T getT (T) {return std::ignore;} // There is a problem with this case.

template <class T, class... Rest> // This overload must precede the next overload for some reason (the other way around will not compile).
T& getT (T, T& returnMe, Rest&...) {return returnMe;} // Since returnMe is of type T.

template <class T, class Discard, class... Rest>
T& getT (T t, Discard&, Rest&... rest) {return getT (t, rest...);} // Since Discard is not the same as T.

template <typename... Ts, typename... Types>
std::tuple<Ts...> tiePackToTuple (std::tuple<Ts...>& tuple, Types&... types) {
return std::tie (getT(Ts{}, types...)...) = tuple;
}

int main() {
std::tuple<int, char, double> tuple1 = std::make_tuple(5, '?', 3.14);
int a; char c; double d;
tiePackToTuple (tuple1, a,c,d);
show(a) show(c) show(d) // a = 5, c = '?', d = 3.14

std::cout << '\n';
int a_, b_; char c_; double d_;
std::tuple<int, char, int, double> tuple2 = std::make_tuple(5, '?', 8, 3.14);
tiePackToTuple (tuple2, d_, a_, c_, b_);
show(a_) show(b_) show(c_) show(d_) // Incorrect (a_ = 8, b_ = gibberish).
// Should be a_ = 5, b_ = 8.
}


The incorrect output in main() is indicated. The problem is that there are two int types, and I want a_ to be the first int (which is 5), and b_ to be the second int (with is 8). Obviously the compiler got confused, but I don't know how to fix that. Also, if I replace std::tuple<int, char, int, double> tuple2 = std::make_tuple(5, '?', 8, 3.14); with



std::tuple<int, char, int, double> tuple2 = std::make_tuple(5, '?', 8, 3.14, false);


It won't compile because my T getT (T) {return std::ignore;} is clearly a problem for the compiler, so I don't know how to insert std::ignore when it needs to be. Any help would be much appreciated.


Aucun commentaire:

Enregistrer un commentaire