I wrote some code that compiles well on recent versions of GCC and Clang, but fails on MSVC:
invalid template argument for template parameter 'TL', expected a class template
Can anyone please explain is this a bug or have I misunderstood something?
Without partial specialization of types_list
it works fine on MSVC too.
#include <cstdint>
#include <type_traits>
namespace detail
{
template <std::size_t Index, typename ...Ts>
struct get
{
static_assert(Index < sizeof...(Ts), "types_list::get index out of bounds");
private:
template <std::size_t CurrentIndex, typename ...Us>
struct helper
{
using type = void;
};
template <std::size_t CurrentIndex, typename U, typename ...Us>
struct helper<CurrentIndex, U, Us...>
{
using type = std::conditional_t<CurrentIndex == Index, U, typename helper<CurrentIndex + 1, Us...>::type>;
};
public:
using type = typename helper<0, Ts...>::type;
};
template <template <typename...> typename TL, typename ...Ts>
struct list_impl
{
inline static constexpr std::size_t size = sizeof...(Ts);
template <std::size_t Index>
using get = typename detail::get<Index, Ts...>::type;
};
}
template <typename ...Ts>
struct types_list : public detail::list_impl<types_list, Ts...>
{
};
template <typename T, typename ...Ts>
struct types_list<T, Ts...> : public detail::list_impl<types_list, T, Ts...>
{
private:
using impl = detail::list_impl<types_list, T, Ts...>;
public:
using front = typename impl:: template get<0>;
using back = typename impl:: template get<impl::size - 1>;
};
using t = types_list<int, double>::front;
using t2 = types_list<int, double>::back;
using t3 = types_list<int, char, double>::get<1>;
int main()
{
t x = 10;
t2 y = 1.4;
t3 z = 'a';
}
EDIT: More detailed example https://pastebin.com/snRC0EPi
It seems to be bug indeed. To refer to the current instantiation you can usually omit the template paramter of the current type. This is what MSVC seems to do here. It causes an error because the template expects a template template parameter.
But why you want to use a template template parameter? For CRTP you use the "bound template type".
If you need to instantiate the template with new parameters this can be done easily with a helper type:
namespace helper{
template<
typename VariadicType
>
class GetTemplateOfVariadicType{
};
template<
template <typename...> typename Template,
typename... Ts
>
class GetTemplateOfVariadicType<Template<Ts...>>
{
public:
template<typename... T>
using type = Template<T...>;
};
}
Usage:
using OtherTL = typename ::helper::GetTemplateOfVariadicType<TL>::template type<int, bool, char>;
See here: godbolt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With