为没有模板参数的可变模板递归创建基本情况 [英] Creating a base case for Variadic Template recursion with no template arguments
问题描述
我正在尝试对可变参数模板使用递归.我希望基本情况具有零模板参数.在查看了之前问题的 stackoverflow 答案后,我发现了对这个问题的两种回应:
I'm trying to use recursion with variadic templates. I would like the base case to have zero template arguments. After looking through stackoverflow answers to previous questions, I have found two kinds of responses to this problem:
- 您不应专门化模板函数.Herb Sutter 在这里写道:http://www.gotw.ca/publications/mill17.htm
- 您使用
模板
或模板
代码>.例如这里的第一个答案:如何编写可变参数模板递归函数?
- You should not specialize templates functions. Herb Sutter wrote about that here: http://www.gotw.ca/publications/mill17.htm
- You use
template <typename = void>
ortemplate <typename T = void>
. For example, the first answer here: How to write a variadic template recursive function?
我尝试在我的问题中使用解决方案 (2),但收到错误.这是一个最小的、可重现的示例:
I attempted to use the solution (2) in my problem, but received errors. This is a Minimal, Reproducible Example:
#include <iostream>
template<typename = void> // base case
int NumArguments() {
return 0;
}
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
class A {
public:
A() {}
};
int main() {
std::cout << NumArguments<A>();
return 0;
}
在 Microsoft Visual C++20 中编译出现错误:
Compilation in Microsoft Visual C++20 gave the errors:
error C2668: 'NumArguments': ambiguous call to overloaded function
message : could be 'int NumArguments<A,>(void)'
message : or 'int NumArguments<A>(void)'
message : while trying to match the argument list '()'
这个错误信息是什么意思?如何使用可变参数模板为递归创建零参数基本情况?
What does this error message mean? How do I create a zero-argument base case for recursion with variadic templates?
评论中要求更完整地描述我的问题.问题确实是问题标题,而不是我如何让我的代码工作?",但我还没有编译我的代码,所以我决定分享它.
There were requests in the comments for a more complete description of my problem. The question really is the question title, and not "how do I get my code to work?", but I have not yet gotten my code to compile, so I have decided to share it.
NumArguments
是另一个函数 ComputeSize
的替代品,它接受输入 Args
并返回一个 std::size_t代码>.
NumArguments
is a stand-in for another function ComputeSize
that takes as input Args
and returns an std::size_t
.
template<typename = void>
constexpr std::size_t ComputeSize() {
return 0;
}
template<typename FirstArg, typename... RemainingArgs>
constexpr std::size_t ComputeSize() {
return FuncReturnSize<FirstArg>() + ComputeSize<RemainingArgs...>();
}
Args
中 Arg
的可能列表是有限的,并且在编译之前是已知的.FuncReturnSize
为每个 Args
重载.例如,两个可能的重载"(?) 是
The possible list of Arg
s in Args
is finite and known prior to compilation. FuncReturnSize
is overloaded for each of these Args
. For example, two possible "overloads"(?) are
template <typename T>
requires ((requires (T t) { { t.Func()} -> std::same_as<double>; }) || (requires (T t) { { t.Func() } -> std::same_as<std::vector<double>>; }))
constexpr std::size_t FuncReturnSize() {
return 1;
}
template <typename T>
requires requires (T t) { { t.Func() } -> is_std_array_concept<>; }
constexpr std::size_t FuncReturnSize() {
return std::tuple_size_v<decltype(std::declval<T&>().Func())>;
}
概念is_std_array_concept<>
应该检查t.Func()
的返回值是否是某个大小的数组.我还不确定它是否有效.它由
The concept is_std_array_concept<>
should check if the return value of t.Func()
is some size array. I am not yet sure if it works. It is defined by
template<class T>
struct is_std_array : std::false_type {};
template<class T, std::size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {};
template<class T>
struct is_std_array<T const> : is_std_array<T> {};
template<class T>
struct is_std_array<T volatile> : is_std_array<T> {};
template<class T>
struct is_std_array<T volatile const> : is_std_array<T> {};
template<typename T>
concept is_std_array_concept = is_std_array<T>::value;
我希望所有这些计算都在编译时完成,所以我已经定义了
I want all of this computation to be done at compile-time, so I have defined
template<std::size_t N>
std::size_t CompilerCompute() {
return N;
}
我现在应该能够像这样在编译时ComputeSize
:
I should now be able to ComputeSize
at compile time like so:
CompilerCompute<ComputeSize<Args...>()>()
推荐答案
这是另一个解决方案(没有专门化),它使用 C++20 requires
子句来解决歧义:
Here's another solution (without specialization), which uses a C++20 requires
clause to resolve the ambiguity:
template <typename... Args> requires (sizeof...(Args) == 0)
constexpr int NumArguments() {
return 0;
}
template<typename FirstArg, typename... RemainingArgs>
constexpr int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
示例:
int main() {
std::cout << NumArguments<int>() << std::endl;
std::cout << NumArguments() << std::endl;
std::cout << NumArguments<float, int, double, char>() << std::endl;
return 0;
}
1
0
4
我使用 concepts
的旧建议是不正确的.此处有一篇关于使用概念和参数包的好帖子.
My old suggestion using concepts
was incorrect. There's a good post here on using concepts and parameter packs.
这篇关于为没有模板参数的可变模板递归创建基本情况的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!