递归可变参数模板的基本案例专业化
Base case specialization for recursive variadic template
我的目标是定义一个 Recursive
class,以 int N
和一种或多种类型 T, ...Ts
为模板,其行为应该类似于 std::pair
与
std::array
个 N
项类型 T
作为 first
,
- 并且,作为
second
,可选 std::vector
of Recursive
实例模板化相同的 N
和剩余的模板参数 Ts...
.
在尝试根据上述要求写下 class 时,我想出了这个无效代码(我还定义了一些必要的,因为它们有很大帮助,别名Recursive
的两个实例化),我不知道我是否错误地设计了我上面描述的内容(或者它是否是一个错误的描述!),或者我是否滥用了语言语法。
#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));
}
我将添加一些我目前已完成的故障排除。在下文中,模板专业化似乎工作得很好。
#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>{}();
}
你的错误是,首先,你声明了 Recursive
接收至少一个整数和 两个 或更多类型,然后,你声明了一个部分特化接收一个整数和恰好 一个 类型。
错误,因为当主模板声明接收两种或更多类型时,专业化不能只接收一种类型。
可以是 counter-intuitive 但解决方案可以声明 Recursive
只接收 一个 类型或更多(这成为递归的基本情况)以及接收 两种 类型或更多
的专业化
template <int N, typename T1, typename...>
struct Recursive : std::array<T1, N>
{ };
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...>>>>
{ };
以下稍作修改(std::size_t
而不是 int
大小;std::optional
而不是 boost::hana::optional
)但完全编译示例
#include <array>
#include <optional>
#include <string>
#include <utility>
#include <vector>
template <std::size_t N, typename T1, typename...>
struct Recursive : std::array<T1, N>
{ };
template <std::size_t N, typename T1, typename T2, typename ...Ts>
struct Recursive<N, T1, T2, Ts...>
: std::pair<std::array<T1, N>,
std::optional<std::vector<Recursive<N, T2, Ts...>>>>
{ };
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main ()
{
Recursive2<int> x{std::array<int, 2u>{0,0}};
Recursive3<int, long> y{{std::array<int, 3u>{0,0,0}, {}}};
}
您有几个问题:
您的专业化与您的主要模板不匹配
template <int N, typename T1, typename T2, typename ...Ts> struct Recursive;
需要至少 3 个参数。我认为它应该是一个专业,主要模板应该是:
template <int N, typename T1, typename ...Ts>
struct Recursive;
template <int N, typename T> struct Recursive<N, T>
的行为不像 std::pair
(正如您陈述的要求,否则您的用法是错误的),您可能想要这样的东西:
template <int N, typename T>
struct Recursive<N, T> : std::pair<std::array<T, N>, decltype(boost::hana::nothing)>
你需要“转发”基础的构造函数class,(组合而不是继承也可能是一个选项,或者定义要使用的类型的特征)或改变方式构造对象。
结果是:
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));
}
我正在添加我自己的答案,因为我确实找到了解决方案(在收到两个答案之前;使用 std::optional
是我根据其中一个答案所做的后期更改)。但是,在我的解决方案中,我 不得不 声明和定义通用模板和专用模板的构造函数,这让我认为它不如其他答案那么好。但是为什么不发呢?
#include <cassert>
#include <iostream>
#include <array>
#include <optional>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
template <int N, typename T, typename ...Ts>
struct Recursive : std::pair<std::array<T, N>,
std::optional<std::vector<Recursive<N, Ts...>>>
> {
template<typename ...Args>
Recursive(Args&& ...args) : std::pair<std::array<T, N>,
std::optional<std::vector<Recursive<N, Ts...>>>
>(args...) {}
};
template <int N, typename T>
struct Recursive<N, T> : std::array<T, N> {
template<typename ...Args>
Recursive(Args&& ...x) : std::array<T, N>(x...) {}
};
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main() {
std::array<std::string, 2> twoStrings{"hello","Hello"};
std::array<char, 2> twoChars{'h', 'H'};
Recursive2<std::string> s{twoStrings};
assert(s == twoStrings);
std::vector<Recursive2<char>> vecOfTwoChars{twoChars, twoChars, twoChars};
Recursive2<std::string, char> sc{twoStrings, vecOfTwoChars};
assert(sc.first == twoStrings);
assert(sc.second->size() == 3);
assert(sc.second == vecOfTwoChars);
assert(sc.second.value()[0] == twoChars);
}
我的目标是定义一个 Recursive
class,以 int N
和一种或多种类型 T, ...Ts
为模板,其行为应该类似于 std::pair
与
std::array
个N
项类型T
作为first
,- 并且,作为
second
,可选std::vector
ofRecursive
实例模板化相同的N
和剩余的模板参数Ts...
.
在尝试根据上述要求写下 class 时,我想出了这个无效代码(我还定义了一些必要的,因为它们有很大帮助,别名Recursive
的两个实例化),我不知道我是否错误地设计了我上面描述的内容(或者它是否是一个错误的描述!),或者我是否滥用了语言语法。
#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));
}
我将添加一些我目前已完成的故障排除。在下文中,模板专业化似乎工作得很好。
#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>{}();
}
你的错误是,首先,你声明了 Recursive
接收至少一个整数和 两个 或更多类型,然后,你声明了一个部分特化接收一个整数和恰好 一个 类型。
错误,因为当主模板声明接收两种或更多类型时,专业化不能只接收一种类型。
可以是 counter-intuitive 但解决方案可以声明 Recursive
只接收 一个 类型或更多(这成为递归的基本情况)以及接收 两种 类型或更多
template <int N, typename T1, typename...>
struct Recursive : std::array<T1, N>
{ };
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...>>>>
{ };
以下稍作修改(std::size_t
而不是 int
大小;std::optional
而不是 boost::hana::optional
)但完全编译示例
#include <array>
#include <optional>
#include <string>
#include <utility>
#include <vector>
template <std::size_t N, typename T1, typename...>
struct Recursive : std::array<T1, N>
{ };
template <std::size_t N, typename T1, typename T2, typename ...Ts>
struct Recursive<N, T1, T2, Ts...>
: std::pair<std::array<T1, N>,
std::optional<std::vector<Recursive<N, T2, Ts...>>>>
{ };
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main ()
{
Recursive2<int> x{std::array<int, 2u>{0,0}};
Recursive3<int, long> y{{std::array<int, 3u>{0,0,0}, {}}};
}
您有几个问题:
您的专业化与您的主要模板不匹配
template <int N, typename T1, typename T2, typename ...Ts> struct Recursive;
需要至少 3 个参数。我认为它应该是一个专业,主要模板应该是:template <int N, typename T1, typename ...Ts> struct Recursive;
template <int N, typename T> struct Recursive<N, T>
的行为不像std::pair
(正如您陈述的要求,否则您的用法是错误的),您可能想要这样的东西:template <int N, typename T> struct Recursive<N, T> : std::pair<std::array<T, N>, decltype(boost::hana::nothing)>
你需要“转发”基础的构造函数class,(组合而不是继承也可能是一个选项,或者定义要使用的类型的特征)或改变方式构造对象。
结果是:
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));
}
我正在添加我自己的答案,因为我确实找到了解决方案(在收到两个答案之前;使用 std::optional
是我根据其中一个答案所做的后期更改)。但是,在我的解决方案中,我 不得不 声明和定义通用模板和专用模板的构造函数,这让我认为它不如其他答案那么好。但是为什么不发呢?
#include <cassert>
#include <iostream>
#include <array>
#include <optional>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
template <int N, typename T, typename ...Ts>
struct Recursive : std::pair<std::array<T, N>,
std::optional<std::vector<Recursive<N, Ts...>>>
> {
template<typename ...Args>
Recursive(Args&& ...args) : std::pair<std::array<T, N>,
std::optional<std::vector<Recursive<N, Ts...>>>
>(args...) {}
};
template <int N, typename T>
struct Recursive<N, T> : std::array<T, N> {
template<typename ...Args>
Recursive(Args&& ...x) : std::array<T, N>(x...) {}
};
template<typename ...T>
using Recursive2 = Recursive<2u, T...>;
template<typename ...T>
using Recursive3 = Recursive<3u, T...>;
int main() {
std::array<std::string, 2> twoStrings{"hello","Hello"};
std::array<char, 2> twoChars{'h', 'H'};
Recursive2<std::string> s{twoStrings};
assert(s == twoStrings);
std::vector<Recursive2<char>> vecOfTwoChars{twoChars, twoChars, twoChars};
Recursive2<std::string, char> sc{twoStrings, vecOfTwoChars};
assert(sc.first == twoStrings);
assert(sc.second->size() == 3);
assert(sc.second == vecOfTwoChars);
assert(sc.second.value()[0] == twoChars);
}