c++ - Cannot explain ambiguous template specializations -
given
template <typename...> struct pack; using t1 = std::tuple<int, char, double>; using t2 = std::tuple<bool, double, int, char>;
tupletree<pack, t1, t2>
shall be
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> >
and extends number of tuples. easy enough understand definition? ok, have program working correctly:
but want extend definition to
`tupletreewithrepeats<p, std::index_sequence<is...>, tuples...>`
where is...
indicate number of times each tuple being used repeatedly until moving on next tuple. note <is...> = <1,1,...,1>
reduce same tupletree<p, tuples...>
. ambiguity i'm stuck these 2 specializations:
tupletreewithrepeatshelper<p, std::index_sequence<is...>, loopnumber, p<ts...>, first, rest...> tupletreewithrepeatshelper<p, std::index_sequence<i, is...>, i, p<ts...>, first, rest...>
for reason, presence of p<ts...>
causes ambiguity because when replace single-named type ambiguity removed. when replace std::index_sequence<is...>
std::index_sequence<i, is...>
, ambiguity still there. what's going on? , how fix this? here code, same 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 type 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 pack, , creates n packs each end tuple's elements, n size of 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 }
as far can tell, these 2 should not ambiguous.
regardless, easy workaround implement "with repeats" in terms of "without repeats":
// tupletreewithrepeats. template <template <typename...> class p, typename tuples> struct tupletreewithrepeatshelper; template <template <typename...> class p, typename... tuples> struct tupletreewithrepeatshelper<p, pack<tuples...>> : identity<tupletree<p, tuples...>> {}; template <template <typename...> class p, typename numrepeats, typename... tuples> struct tupletreewithrepeats; template <template <typename...> class p, std::size_t... is, typename... tuples> struct tupletreewithrepeats<p, std::index_sequence<is...>, tuples...> : tupletreewithrepeatshelper<p, typename mergepacks<repeat<tuples, is>...>::type> {};
where repeat
is
template<class t, std::size_t> using id = t; template<class t, std::size_t... is> pack<id<t, is>...> do_repeat(std::index_sequence<is...>); template<class t, std::size_t i> using repeat = decltype(do_repeat<t>(std::make_index_sequence<i>()));
demo. 1 might argue better design.
minimized to:
template<class> class purr { }; template <template <class> class, class> struct meow; template <template <class> class p> struct meow<p, p<int>> { }; template <template <class> class p, class t> struct meow<p, p<t>> { }; meow<purr, purr<int>> c;
gcc reports ambiguity, looks bug me. clang handles correctly.
Comments
Post a Comment