使用概念检测空参数包 [英] Using concepts to detect empty parameter packs

查看:32
本文介绍了使用概念检测空参数包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

回答another question 我发布了,Jack Harwood 分享了一个很好的解决方案,使用概念检测空的可变参数包.示例问题是使用递归计算参数包参数的数量.我在下面重现了他的解决方案.

In an answer to another question I posted, Jack Harwood shared a nice solution to detect empty variadic parameter packs using concepts. The example problem is to compute the number of parameter pack arguments using recursion. I reproduce his solution below.

template <typename... Args>
concept NonVoidArgs = sizeof...(Args) > 0;

template <typename... Args>
concept VoidArgs = sizeof...(Args) == 0;

template <VoidArgs...>
constexpr int NumArguments() {
    return 0;
}

template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments() {
    return 1 + NumArguments<RemainingArgs...>();
}

示例:

int main() {
    std::cout << NumArguments<int>() << std::endl; // 1
    std::cout << NumArguments() << std::endl; // 0
    std::cout << NumArguments<float, int, double, char>() << std::endl; // 4
    return 0;
}

我认为这是比使用类模板来专门化函数模板更好的解决方案.但是,我不确定它为什么有效.模板函数

I think that this is a better solution than using class templates to specialize function templates. However, I'm not sure why it works. The template function

template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments()

似乎至少需要两个模板参数.需要有一个 FirstArg,然后至少有 1 个 RemainingArgs.当只有一个模板参数时,为什么编译器会调用这个重载(?)?这种行为是否会给此解决方案带来任何问题?

seems to require at least two template arguments. There needs to be a FirstArg and then at least 1 RemainingArgs. Why does the compiler call this overload(?) when there is only one template argument? Does this behavior create any problems with this solution?

推荐答案

概念本身是正确的,但问题是示例使用它们不正确并且本身存在错误.在给定的代码中,概念是基于参数而不是整个参数包.

The concepts themselves are correct but the problem is that the example uses them incorrectly and is itself faulty. In the given code the concept is imposed on an argument basis instead of the entire parameter pack.

您当前的版本

template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments() {
  return 1 + NumArguments<RemainingArgs...>();
}

实际上相当于一个requires子句和一个折叠表达式

is actually equivalent to a requires clause and a fold expression

template<typename FirstArg, typename... RemainingArgs>
int NumArguments() requires (NonVoidArgs<RemainingArgs> && ...) {
  return 1 + NumArguments<RemainingArgs...>();
}

这实际上意味着您正在定义一个函数,该函数必须有一个参数 FirstArg,并且可能有一个任意大小的附加参数包 RemainingArgs(包括零!).如果这些参数中的每一个 - 如果存在 - 然后独立检查它是否满足 NonVoidArgs 概念,这当然总是正确的.这意味着函数基本上退化为

This actually means you are defining a function that must have an argument FirstArg and might have an additional parameter pack of arbitrary size RemainingArgs (including zero!). Each of these arguments - if present - is then checked independently if it fulfills the NonVoidArgs concept which of course is always true. This means the function basically degenerates to

template<typename FirstArg, typename... RemainingArgs>
int NumArguments() {
  return 1 + NumArguments<RemainingArgs...>();
}

话虽如此,实际上参数包甚至不需要 NonVoidArgs:在这里试试吧!

That being said it is actually not even necessary for the parameter pack to be NonVoidArgs: Try it here!

不仅对单个模板参数的数据类型而且对整个参数包施加限制的正确方法实际上是一个 requires 子句,如下所示:

The correct way to impose restrictions not only on the data type of a single template argument but the entire parameter pack would actually be a requires clause as follows:

template<typename FirstArg, typename... RemainingArgs>
int NumArguments() requires NonVoidArgs<RemainingArgs...> {
  return 1 + NumArguments<RemainingArgs...>();
}

正如预期的那样,这行不通:在这里试试!代码很幸运,它实际上有效,因为它们没有正确执行这些概念.这个概念背后的基本思想是有缺陷的.

As expected this would not work: Try it here! I guess the person who has written the code was just lucky it actually works as they did not enforce the concepts correctly. The basic idea behind the concept is flawed.

这篇关于使用概念检测空参数包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆