想象一下这段代码:
#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;
}
首先打印
输出:
DBL!!! 1.1 2 3.3 4
我的期望是,它会输出 DBL!!! 3.3 之前或没有 DBL!!!根本。但为什么是一个???
第二个打印
输出:
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...); }
关于c++ - Variadic template 选择更通用的模板而不是重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42557883/