c++ - 使用概念检测空参数包
问题描述
在回答我发布的另一个问题时,Jack Harwood 分享了一个很好的解决方案,可以使用概念检测空的可变参数包。示例问题是使用递归计算参数包参数的数量。我在下面复制了他的解决方案。
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;
}
我认为这是一个比使用类模板专门化功能模板更好的解决方案。但是,我不确定它为什么会起作用。模板函数
template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments()
似乎至少需要两个模板参数。需要有 a FirstArg
,然后至少有 1 RemainingArgs
。当只有一个模板参数时,为什么编译器会调用这个重载(?)?此行为是否会对此解决方案产生任何问题?
解决方案
这些概念本身是正确的,但问题是该示例错误地使用了它们并且本身就是错误的。在给定的代码中,概念是基于参数而不是整个参数包。
您当前的版本
template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
实际上相当于一个requires
子句和一个折叠表达式
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() requires (NonVoidArgs<RemainingArgs> && ...) {
return 1 + NumArguments<RemainingArgs...>();
}
这实际上意味着您正在定义一个必须有参数的函数,FirstArg
并且可能有一个任意大小的附加参数包RemainingArgs
(包括零!)。这些参数中的每一个 - 如果存在 - 然后独立检查它是否满足NonVoidArgs
当然总是正确的概念。这意味着函数基本上退化为
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
话虽如此,参数包实际上甚至没有必要NonVoidArgs
:在这里试试!
不仅对单个模板参数的数据类型而且对整个参数包施加限制的正确方法实际上是一个requires
子句,如下所示:
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() requires NonVoidArgs<RemainingArgs...> {
return 1 + NumArguments<RemainingArgs...>();
}
正如预期的那样,这不起作用:在这里试试!我想编写代码的人很幸运,因为他们没有正确执行这些概念,所以它实际上可以工作。这个概念背后的基本思想是有缺陷的。
推荐阅读
- react-native - 在 React-Native 中的子组件(即当前应用程序)中获取父组件(存在于另一个应用程序中)的 onScroll 事件
- java - 是否可以将 pushID 绑定到 Firebase 数据库中的 userUid
- c++ - c++ *(Type*) 属性名
- python - 如何在 jupyter notebbok 中访问内核变量
- android - Android:更改联系人时,带有广播接收器的前台服务停止工作
- c++ - 对象是 C++ 中的存储位置还是值?
- node.js - 我可以使用“AND”来连接或创建棱镜的位置吗?
- jquery - JQuery 每个输入函数都停在最后一个元素而不是前一个元素
- python - 如何为在同一台机器上运行的客户端和服务器设置不同的 IP?
- php - 记录更新、事务死锁