Compte tenune peut expliquer la spécialisation du modèle ambigu
template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
TupleTree<Pack, T1, T2>
sont
Pack<
Pack<int, bool>, Pack<int, double>, Pack<int, int>, Pack<int, char>,
Pack<char, bool>, Pack<char, double>, Pack<char, int>, Pack<char, char>,
Pack<double, bool>, Pack<double, double>, Pack<double, int>, Pack<double, char>
>
Et cela s'étend à un certain nombre de tuples. Assez facile à comprendre la définition? D'accord, j'ai fonctionner correctement le programme:
Mais maintenant, je veux étendre la définition à
`TupleTreeWithRepeats<P, std::index_sequence<Is...>, Tuples...>`
où Is...
indique le nombre de fois que chaque tuple est utilisé de façon répétée jusqu'à ce que le déplacement sur le prochain tuple. Notez que <Is...> = <1,1,...,1>
réduira au même que TupleTree<P, Tuples...>
. L'ambiguïté que je suis coincé avec est avec ces deux spécialisations:
TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, P<Ts...>, First, Rest...>
TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...>
Pour une raison quelconque, la présence de P<Ts...>
provoque l'ambiguïté parce que quand je le remplace par un seul type nommé l'ambiguïté est supprimée. Même lorsque je remplace std::index_sequence<Is...>
par std::index_sequence<I, Is...>
, l'ambiguïté est toujours là. Que se passe-t-il? Et comment résoudre ce problème? Voici le code, ce qui est presque le même que celui pour TupleTree
:
#include <iostream>
#include <tuple>
#include <type_traits>
template <typename T> struct Identity { using type = T; };
// Merging packs of types.
template <typename...> struct MergePacks;
template <typename Pack>
struct MergePacks<Pack> : Identity<Pack> {};
template <template <typename...> class P, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P<Types1...>, P<Types2...>, Packs...> : MergePacks<P<Types1..., Types2...>, Packs...> {};
// Appending a type to a pack.
template <typename Pack, typename T> struct AppendType;
template <template <typename...> class P, typename... Ts, typename T>
struct AppendType <P<Ts...>, T> {
using type = P<Ts..., T>;
};
// ExpandPackWithTuple takes a pack, and creates N packs that each end with the tuple's elements, N is the size of the tuple.
template <template <typename...> class P, typename Pack, typename Tuple, typename Indices> struct ExpandPackWithTupleHelper;
template <template <typename...> class P, typename Pack, typename Tuple, std::size_t... Is>
struct ExpandPackWithTupleHelper<P, Pack, Tuple, std::index_sequence<Is...>> {
using type = P<typename AppendType<Pack, typename std::tuple_element<Is, Tuple>::type>::type...>;
};
template <template <typename...> class P, typename Pack, typename Tuple>
using ExpandPackWithTuple = typename ExpandPackWithTupleHelper<P, Pack, Tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>>::type;
// TupleTreeWithRepeats.
template <template <typename...> class P, typename NumRepeats, std::size_t LoopNumber, typename OutputPack, typename... Tuples> struct TupleTreeWithRepeatsHelper;
template <template <typename...> class P, std::size_t I, std::size_t... Is, std::size_t LoopNumber, typename... Ts, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, LoopNumber, P<Ts...>, First, Rest...> :
TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, LoopNumber + 1, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, First, Rest...> {};
template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Ts, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...> :
TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 0, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, Rest...> {};
template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename OutputPack>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, OutputPack> {
using type = OutputPack;
};
template <template <typename...> class P, typename NumRepeats, typename... Tuples> struct TupleTreeWithRepeats;
template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Tuples>
struct TupleTreeWithRepeats<P, std::index_sequence<I, Is...>, Tuples...> : TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 0, P<P<>>, Tuples...> {};
// Testing
template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
using T3 = std::tuple<double, int>;
int main() {
std::cout << std::is_same<
TupleTreeWithRepeats<Pack, std::index_sequence<1,1,1>, T1, T2, T3>::type,
Pack<
Pack<int, bool, double>, Pack<int, bool, int>, Pack<int, double, double>, Pack<int, double, int>, Pack<int, int, double>, Pack<int, int, int>, Pack<int, char, double>, Pack<int, char, int>,
Pack<char, bool, double>, Pack<char, bool, int>, Pack<char, double, double>, Pack<char, double, int>, Pack<char, int, double>, Pack<char, int, int>, Pack<char, char, double>, Pack<char, char, int>,
Pack<double, bool, double>, Pack<double, bool, int>, Pack<double, double, double>, Pack<double, double, int>, Pack<double, int, double>, Pack<double, int, int>, Pack<double, char, double>, Pack<double, char, int>
>
>::value << '\n'; // ambiguous
}
Fait intéressant, il est pas ambigu pour clang: http: //coliru.stacked -crooked.com/a/4272e7d68f252d6e –
Je compile avec GCC 5.1. En passant, j'ai légèrement modifié mon code, car j'ai repéré une erreur de logique dans la deuxième spécialisation. Mais l'ambiguïté est toujours le principal problème.Mais l'ambiguïté doit d'abord être supprimée avant d'affiner les spécialisations et de tester la sortie. – prestokeys
@MarcoA. Je pense que la compilation a simplement dépassé ce délai. En regardant la sortie avec moins de profondeur, on dirait que clang descendait une récursion infinie. –