Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Someone explain why the ambiguity here, please?

Fill<T, Pack, Size, Value> is to be the type Pack<Value, Value, ..., Value>, where Value is repeated Size times. Can someone explain, why this is ambiguous?

template <typename T, template <T...> class Pack, int Size, int Count, typename Output, T Value>
struct FillHelper;

template <typename T, template <T...> class P, int Size, int Count, T... Output, T Value>
struct FillHelper<T, P, Size, Count, P<Output...>, Value> :
    FillHelper<T, P, Size, Count + 1, P<Output..., Value>, Value> {};

template <typename T, template <T...> class P, int Size, T... Output, T Value>
struct FillHelper<T, P, Size, Size, P<Output...>, Value> {
    using type = P<Output...>;
};

template <typename T, template <T...> class P, int Size, T Value>
using Fill = typename FillHelper<T, P, Size, 0, P<>, Value>::type;

template <int...> struct Pack;

int main() {
    using T = Fill<int, Pack, 10, 4>;
}

while this is not:

template <typename T, int Size, int Count, typename Output, T Value>
struct FillHelper;

template <typename T, template <T...> class P, int Size, int Count, T... Output, T Value>
struct FillHelper<T, Size, Count, P<Output...>, Value> :
    FillHelper<T, Size, Count + 1, P<Output..., Value>, Value> {};

template <typename T, template <T...> class P, int Size, T... Output, T Value>
struct FillHelper<T, Size, Size, P<Output...>, Value> {
    using type = P<Output...>;
};

template <typename T, template <T...> class P, int Size, T Value>
using Fill = typename FillHelper<T, Size, 0, P<>, Value>::type;

template <int...> struct Pack;

int main() {
    using T = Fill<int, Pack, 10, 4>;
}

It turns out that I indirectly noticed that the second is shorter and thus better than the first, but I was baffled why the first one would not compile. I get error with GCC 4.9.2, which is very recent. Error with Visual Studio 2013 too. A better solution than the second code is welcomed, by the way.

Update: Reducing the problem further, it turns out that the presence of the template-template in the specializations is NOT the problem, because this DOES compile with GCC 4.9.2 (and Visual Studio 2013 too):

template <typename T, template <T...> class Pack, int Size, int Count>
struct F;

template <typename T, template <T...> class P, int Size, int Count>
struct F : F<T, P, Size, Count + 1> {};

template <typename T, template <T...> class P, int Size>
struct F<T, P, Size, Size> {
    using type = int;
};

template <int...> struct Pack;

int main() {
    using T = F<int, Pack, 10, 0>::type;
}

So what exactly is the problem in the first code that is causing confusion with GCC and VS?

like image 944
prestokeys Avatar asked Nov 10 '22 15:11

prestokeys


1 Answers

I don't know why gcc rejects your code, but if you have C++14 support, a less tedious solution is to use std::make_index_sequence to construct a pack with Size elements, then deduce the pack and expand it again, like so:

template <typename T, template <T...> class Pack, T Value, size_t... indices>
auto FillHelper(std::index_sequence<indices...>) -> Pack<(indices, Value)...>;

template <typename T, template <T...> class P, int Size, T Value>
using Fill = decltype(FillHelper<T, P, Value>(std::make_index_sequence<Size>()));

Link: http://coliru.stacked-crooked.com/a/7771560a1f32461d

like image 184
Brian Bi Avatar answered Nov 15 '22 05:11

Brian Bi