鉴于std::tuple<Ts...> tuple
和一包类型Types... types
,我们希望执行std::tie(_types...) = tuple
,其中_types...
通过重新排序从types...
获得,以便std::tie(_types...) = tuple;
将有意义(std::ignore
如果_types...
中找不到与types...
中的任何类型相匹配的话,则会Ts...
插入template <typename... Ts, typename... Types>
std::tuple<Ts...> tiePackToTuple (const std::tuple<Ts...>& tuple, Types&... types);
。我正在调用此功能
#include <iostream>
#include <tuple>
#define show(variable) std::cout << #variable << " = " << variable << std::endl;
template <typename T>
T getT (T) {return std::ignore;} // There is a problem with this case.
template <typename T, typename... 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 <typename T, typename Discard, typename... 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 (const 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, d,a,c);
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.
}
这是我到目前为止所拥有的。
std::tuple<int, char, int, double> tuple2 = std::make_tuple(5, '?', 8, 3.14);
指示main()中的输出错误。问题是有两种int类型,我希望a_成为第一个int(即5),b_是第二个int(带有8)。显然编译器感到困惑,但我不知道如何解决这个问题。
另一个问题是,如果我用
替换main()中的std::tuple<int, char, int, double, bool> tuple2 = std::make_tuple(5, '?', 8, 3.14, false);
T getT (T) {return std::ignore;}
它不会编译,因为我的std::ignore
显然是编译器的问题,因此我不知道如何在需要插入{{1}}时插入它。怎么做那部分?任何帮助将不胜感激。
答案 0 :(得分:0)
更新:T.C.解决了这个问题。我们现在可以使这个问题更加有趣:
鉴于std::tuple<Ts...> tuple
和一包类型Types... types
,我们希望执行std::tie(types...) = tuple'
,其中tuple'
从tuple
获得以下意义:
假设Types...
为{int, char, int, int, double, int, int, bool, int}
且tuple = {0.1,3,4,'?'}
属于std::tuple<double,int,int,char>
类型。
然后tuple'
将是std::make_tuple(3,'?',4,3,0.1,4,3,bool(),4)
。请注意,Types...
中不存在tuple
中不存在的类型的默认构造函数。
这是我对T.C。解决方案的概括(归功于他的原因),但默认的构造函数案例还没有被覆盖。
更新:现在处理的默认构造函数案例。无法想到任何进一步的概括,所以我会在这里结束。
#include <iostream>
#include <tuple>
#include <type_traits>
#define show(variable) std::cout << #variable << " = " << variable << std::endl;
template <std::size_t...> struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence_helper : make_index_sequence_helper<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence_helper<0, Is...> {
using type = index_sequence<Is...>;
};
template <std::size_t N>
using make_index_sequence = typename make_index_sequence_helper<N>::type;
// Given a pack of types Z, a number N, and a type T, count the number of times T appears in the first N types of Z.
template <std::size_t, typename, typename, std::size_t Count = 0> struct CountInFirstN;
template <std::size_t N, typename T, template <typename...> class Z, std::size_t Count, typename First, typename... Rest>
struct CountInFirstN<N, T, Z<First, Rest...>, Count> : CountInFirstN<N-1, T, Z<Rest...>, Count> {};
template <std::size_t N, template <typename...> class Z, typename T, std::size_t Count, typename... Rest>
struct CountInFirstN<N, T, Z<T, Rest...>, Count> : CountInFirstN<N-1, T, Z<Rest...>, Count+1> {};
template <typename T, template <typename...> class Z, std::size_t Count, typename First, typename... Rest>
struct CountInFirstN<0, T, Z<First, Rest...>, Count> : std::integral_constant<std::size_t, Count> {};
template <typename T, template <typename...> class Z, std::size_t Count, typename... Rest>
struct CountInFirstN<0, T, Z<T, Rest...>, Count> : std::integral_constant<std::size_t, Count> {}; // Without this, there will be ambiguity compiling error with CountInFirstN<N, T, Z<T, Rest...>, Count>.
// Given a pack of types Z, a 0-based number N, and a type T, determine the index of the Nth T in Z.
template <std::size_t, typename, typename, std::size_t = 0> struct GetIndexInPack;
template <std::size_t N, typename T, template <typename...> class Z, std::size_t V, typename First, typename... Rest>
struct GetIndexInPack<N, T, Z<First, Rest...>, V> : GetIndexInPack<N, T, Z<Rest...>, V+1> {};
template <std::size_t N, template <typename...> class Z, typename T, std::size_t V, typename... Rest>
struct GetIndexInPack<N, T, Z<T, Rest...>, V> : GetIndexInPack<N-1, T, Z<Rest...>, V+1> {};
template <typename T, template <typename...> class Z, std::size_t V, typename... Rest>
struct GetIndexInPack<0, T, Z<T, Rest...>, V> : std::integral_constant<std::size_t, V> {}; // The T's must match so that when N is 1, we get the value immediately through inheritence from GetIndexInPack<0, T, Z<T, Rest...>, V>.
constexpr std::size_t NOT_FOUND = -1;
template <std::size_t N, typename T, template <typename...> class Z, std::size_t V>
struct GetIndexInPack<N, T, Z<>, V> : std::integral_constant<std::size_t, NOT_FOUND> {};
// NumTypes<T, Z<Types...>::value is the number of times T occurs in Types...
template <typename, typename, std::size_t = 0> struct NumTypes;
template <typename T, template <typename...> class Z, typename First, typename... Rest, std::size_t Count>
struct NumTypes<T, Z<First, Rest...>, Count> : NumTypes<T, Z<Rest...>, Count> {};
template <typename T, template <typename...> class Z, typename... Rest, std::size_t Count>
struct NumTypes<T, Z<T, Rest...>, Count> : NumTypes<T, Z<Rest...>, Count+1> {};
template <typename T, template <typename...> class Z, std::size_t Count>
struct NumTypes<T, Z<>, Count> : std::integral_constant<std::size_t, Count> {};
// Given a pack of types Z, produce a list of numbers Ns, where Ns[i] is the number of times Z[i] has appeared in the first i items in Z.
template <typename, typename, typename> struct GenerateCounts;
template <template <typename...> class Z, typename... Types, typename... Ts, std::size_t... Is>
struct GenerateCounts<Z<Types...>, Z<Ts...>, index_sequence<Is...>> :
index_sequence<CountInFirstN<Is % (NumTypes<Types, Z<Ts...>>::value + 1), Types, Z<Types...>>::value...> {};
// GetTupleElement is needed to take care of the default constructor case, in the event that GetIndexInPack<Count, Type, std::tuple<Ts...>>::value == NOT_FOUND.
template <std::size_t N, typename Type, typename... Ts>
struct GetTupleElementHelper {
static Type get (const std::tuple<Ts...>& tuple) {return std::get<N>(tuple);}
};
template <typename Type, typename... Ts>
struct GetTupleElementHelper<NOT_FOUND, Type, Ts...> {
static Type get (const std::tuple<Ts...>& tuple) {return Type();}
};
template <std::size_t Count, typename Type, typename... Ts>
struct GetTupleElement {
static Type get (const std::tuple<Ts...>& tuple) {
constexpr std::size_t index = GetIndexInPack<Count, Type, std::tuple<Ts...>>::value;
return GetTupleElementHelper<index, Type, Ts...>::get(tuple); // 'return index == NOT_FOUND ? Type() : std::get<index>(tuple);' will not compile because both are evaluated.
}
};
// Now tieAnyPackToTuple itself.
template <typename... Ts, typename... Types, std::size_t... Counts>
void tieAnyPackToTupleHelper (const std::tuple<Ts...>& tuple, index_sequence<Counts...>, Types&... types) {
std::tie(types...) = std::make_tuple (GetTupleElement<Counts, Types, Ts...>::get(tuple)...);
}
template <typename... Ts, typename... Types>
void tieAnyPackToTuple (const std::tuple<Ts...>& tuple, Types&... types) {
tieAnyPackToTupleHelper (tuple, GenerateCounts<std::tuple<Types...>, std::tuple<Ts...>, make_index_sequence<sizeof...(Types)>>{}, types...);
}
int main() {
std::cout << NumTypes<int, std::tuple<int, char, int, int, double, int, int, bool, int>>::value << std::endl; // 6
std::tuple<int, char, double> tuple1 = std::make_tuple(5, '?', 3.14);
int a; char c; double d;
tieAnyPackToTuple (tuple1, d,a,c);
show(a) show(c) show(d) // a = 5, c = '?', d = 3.14
std::cout << '\n';
int m, n, r, s, t, u; char p; double q;
std::tuple<int, char, int, double> tuple2 = std::make_tuple(5, '?', 8, 3.14);
tieAnyPackToTuple (tuple2, q, m, n, p);
show(m) show(n) show(p) show(q) // m = 5, n = 8, p = '?', q = 3.14
std::cout << '\n';
tieAnyPackToTuple (tuple2, m, p, n, r, q, s, t, u);
show(m) show(n) show(p) show(q) show(r) show(s) show(t) show(u) // m = 5, n = 8, p = '?', q = 3.14, r = 5, s = 8, t = 5, u = 8
bool z; long l;
tieAnyPackToTuple (tuple2, m, p, l, n, r, q, s, t, z, u); // l is long and z is bool but there is no long or bool element in tuple2.
show(l) std::cout << std::boolalpha << "z = " << z << std::endl; // l = 0, z = false (the default values of long and bool).
}