variadic模板选择了更多常见的模板而不是过载
Variadic template chooses more common template instead of overload
想象此代码:
#include <iostream>
void PrintInternal() {
std::cout << std::endl;
}
template <typename T, typename...ARGS>
void PrintInternal(const T& head, const ARGS&...rest) {
std::cout << head << " ";
PrintInternal(rest...);
};
template <typename...ARGS>
void PrintInternal(const double& head, const ARGS&...rest) {
std::cout << "DBL!!! " << head << " ";
PrintInternal(rest...);
}
template <typename...ARGS>
void Print(const ARGS&...args) {
PrintInternal(args...);
}
int main() {
Print(1.1, 2, 3.3, 4);
Print(0, 1.1, 2, 3.3, 4);
return 0;
}
第一个Print
输出:
dbl !!!1.1 2 3.3 4
我的期望是,它将输出DBL !!!在3.3或没有DBL之前!!!根本。但是为什么一个?
第二个Print
输出:
0 1.1 2 3.3 4
为什么没有DBL !!!像我们在第一个示例中有一个。
,如果我们有一个。以及如何实现,对于每个double
,我将在没有部分专业化的情况下输出一些不同的东西?我以为,简单的超载应该可以...
链接到cpp.sh以查看汇编结果 -> http://cpp.sh/42cz
PrintInternal()
查找的查找将要找到两种函数:
- 在函数模板的定义点可见的所有函数。
- 功能模板的相关参数的关联名称空间中的所有函数。
在这种情况下,我们所有的论点都是基本类型,因此没有任何关联的名称空间。这使事情变得更容易。因此,当我们从:
开始时#include <iostream>
void PrintInternal() { // #1
std::cout << std::endl;
}
template <typename T, typename...ARGS>
void PrintInternal(const T& head, const ARGS&...rest) { // #2
std::cout << head << " ";
PrintInternal(rest...); // <== (*)
};
template <typename...ARGS>
void PrintInternal(const double& head, const ARGS&...rest) { // #3
std::cout << "DBL!!! " << head << " ";
PrintInternal(rest...);
}
标记为PrintInteral()
的呼叫只有两个候选者:nullary函数(#1)和本身(#2)。另一个是,更专业的PrintInteral()
尚未看到const double&
(#3),因此从未被视为候选人。并不是说#2比#3首选,而是它是唯一的选择。
如果您翻转两个过载的订购,那么您将遇到不同的问题 - 您将找不到#2!
这为您提供了一些选择:
- 将单个元素与打印所有元素的打印分开。这样,您只需要超载
PrintSingle()
,这很容易做到。 - 向前删除您所有的功能模板,以使它们都可见。
仅出于最高点上的第二个子弹点的目的而引入另一个参数。只是一个虚拟论点,只是为了与ADL进行名称查找。该解决方案有时是必要的,但总是令人困惑:
namespace N { struct adl { }; void PrintInternal(adl ) { std::cout << std::endl; } template <typename T, typename...ARGS> void PrintInternal(adl, const T& head, const ARGS&...rest) { std::cout << head << " "; PrintInternal(adl{}, rest...); } template <typename...ARGS> void PrintInternal(adl, const double& head, const ARGS&...rest) { std::cout << "DBL!!! " << head << " "; PrintInternal(adl{}, rest...); } } template <typename...ARGS> void Print(const ARGS&...args) { PrintInternal(N::adl{}, args...); }
您有可见性问题,您可以通过向前声明进行修复:
template <typename...ARGS> void PrintInternal(const double& head, const ARGS&...rest);
template <typename T, typename...ARGS>
void PrintInternal(const T& head, const ARGS&...rest) {
std::cout << head << " ";
PrintInternal(rest...);
}
template <typename...ARGS>
void PrintInternal(const double& head, const ARGS&...rest) {
std::cout << "DBL!!! " << head << " ";
PrintInternal(rest...);
}
演示
更简单的是只有特定于简单印刷品的特定,并将递归分开,类似于:
void printSingle(double d)
{
std::cout << "DBL!!! " << d << " ";
}
template <typename T>
void printSingle(const T& t)
{
std::cout << t << " ";
}
template <typename...ARGS>
void Print(const ARGS&...args) {
const int dummy[] = {0, (printSingle(args), 0)...};
static_cast<void>(dummy); // Avoid warning for unused variable
std::cout << std::endl;
}
demo
相关文章:
- 如何使用默认参数等选择模板专业化
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 选择要调用的构造函数
- C++选择排序算法中的逻辑错误
- QTreeView幻灯片多选后无法使用单击选择
- 无法获取菜单选择以运行函数.C++
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- Variadic模板未编译
- 在C++中,如何通过几种类型从元组中选择多个元素
- 讨论 - 创建矩阵时的数组与向量的向量 - 什么是最实用的选择
- variadic模板中的模板参数推导失败
- 对可变参数使用声明.如何选择正确的功能
- 选择选举获胜者的程序
- 如何选择在 csv 文件中输出的位置
- 根据用户回答声明"Players"。用户选择玩家数量。播放器是结构体
- 程序在尝试猜测它选择的随机数时进入无限循环?
- 选择和修改嵌套向量中的条目的最佳实践
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- variadic模板选择了更多常见的模板而不是过载