My target is to define a Recursive
class, templated on an int N
and one or more types T, ...Ts
, which should behave like a std::pair
with
std::array
of N
items of type T
as the first
,second
, an optional std::vector
of Recursive
instances templated on the same N
and on the remaining template arguments Ts...
.In trying to write down the class given the above requirements, I've come up with this non-working code (where I've also defined some necessary, as they help a lot, aliases for two instantiations of Recursive
), and I don't know if I have mis-designed what I described above (or if it is an ill-formed description!), or if I'm misusing the language syntax.
#include <array>
#include <boost/hana/fwd/optional.hpp>
#include <boost/hana/optional.hpp>
#include <string>
#include <utility>
#include <vector>
template <int N, typename T1, typename T2, typename ...Ts>
struct Recursive
: std::pair<std::array<T1, N>,
boost::hana::optional<std::vector<Recursive<N, T2, Ts...>>>> {};
template <int N, typename T>
struct Recursive<N, T> : std::array<T, N> {};
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main() {
using boost::hana::nothing;
Recursive2<int> x(std::make_pair(std::array<int, 2>{0,0}, nothing));
}
I'll add some troubleshooting that I've done so far. In the following the template specilization seems to work just fine.
#include <iostream>
template <int N, typename T, typename ...Ts>
struct Recursive {
void operator()(){ std::cout << "general\n"; }
};
template <int N, typename T>
struct Recursive<N, T> {
void operator()(){ std::cout << "specialized\n"; }
};
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main() {
Recursive2<int>{}();
Recursive2<int>{}();
Recursive2<int,int>{}();
}
You have several issues:
Your specialization doesn't match your primary template
template <int N, typename T1, typename T2, typename ...Ts> struct Recursive;
requires at least 3 parameters. I think it should be a specialization and primary template should be:
template <int N, typename T1, typename ...Ts>
struct Recursive;
template <int N, typename T> struct Recursive<N, T>
doesn't behave like a std::pair
(as you state your requirement, else your usage is wrong), you probably want something like:
template <int N, typename T>
struct Recursive<N, T> : std::pair<std::array<T, N>, decltype(boost::hana::nothing)>
You need to "forward" the constructors of the base class, (Composition instead of inheritance might be an option too, or traits to define type to use) or change way to construct the object.
Result is:
template <int N, typename T1, typename ...Ts>
struct Recursive;
template <int N, typename T1, typename T2, typename ...Ts>
struct Recursive<N, T1, T2, Ts...>
: std::pair<std::array<T1, N>,
boost::hana::optional<std::vector<Recursive<N, T2, Ts...>>>
>
{
using std::pair<
std::array<T1, N>,
boost::hana::optional<std::vector<Recursive<N, T2, Ts...>>>>::pair;
};
template <int N, typename T>
struct Recursive<N, T>
: std::pair<std::array<T, N>, decltype(boost::hana::nothing)>
{
using std::pair<std::array<T, N>, decltype(boost::hana::nothing)>::pair;
};
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main() {
using boost::hana::nothing;
Recursive2<int> x(std::make_pair(std::array<int,2>{0,0}, nothing));
}