I'm trying to do an advanced class template argument deduction by using the new deduction guides from c++17. Unfortunately, it looks like you can only use simple template declarations after the ->
, but I need a helper struct to determine the resulting type.
My use case is this one: I have a variadic template class that takes an arbitrary amount of different types. For one constructor I want to specify every single one, for another ctor I want to specify only one type and replicate it N times.
To access this N
in the deduction guide I introduced a new type:
template<size_t N>
struct Replicate { };
The class I have is similar this one:
template<typename... Foos>
struct Foo {
// [ ... ] member std::tuple<Foos...>
// ctor 1: give values for all types (easy to deduce)
Foo(Foos&&... args /* rvalue ref, NOT forwarding */) { };
// ctor 2: give one value and N, result is N copies of this value.
// takes Replicate<N> as parameter to aid the deduction.
template<typename T, size_t N>
Foo(const T& t, Replicate<N>) { };
};
The usage would be like this:
Foo f1{1, 2, 3.0}; // deduce Foo<int, int, double>;
Foo f2{8, Replicate<4>{}}; // deduce Foo<int, int, int, int>;
The deduction guide for the first one is straight forward:
template<typename... Ts>
Foo(Ts&&...) -> Foo<Ts...>;
It gets problematic with the second (ctor 2) deduction guide. First I need a helper struct to create Foo<T, T, ... /* total N times */, T>
from T
and N
.
template<typename, typename, typename>
struct ExpandNTimes;
template<typename T, size_t... Is>
struct ExpandNTimes<T, std::index_sequence<Is...>> {
template<size_t> using NthType = T;
using Type = Foo<NthType<Is>...>;
};
Then in the deduction guide I want to utilize the helper to deduce the correct type. I cant directly use Foo<something>
as there is no kind of "in place parameter pack creation", therefore the helper struct.
template<typename T, size_t N>
Foo(const T&, Replicate<N>) -> typename ExpandNTimes<T, std::make_index_sequence<N>>::Type;
Unfortunately this results int an error similar to this one:
error: trailing return type of 'typename ExpandNTimes<T, /* std things */>::Type' deduction guide is not a specialization of ‘Foo<Ts>’
Is there any way to work around this issue?
This is impossible with class template argument deduction - both template names must be the same, and the thing after the ->
must be a simple-template-id. This doesn't leave any room for template shenanigans.
But nothing prevents you from doing the thing that class template argument deduction is intended to replace: factory functions:
template <typename T, size_t N>
typename ExpandNTimes<T, std::make_index_sequence<N>>::Type
makeFoo(T const&, Repliace<N>);
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