c++中重载递归函数的模板推导规则
rule for template deduction for overloaded recursive function in c++
我发现了很多关于模板推导的信息(例如C++模板函数重载规则(,但这并不能帮助我理解重载递归函数的模板推导行为。在下面的代码中,我真的不明白编译器是如何推断出它应该为vectvect
使用vector<T>
函数两次,为pairpair
使用pair<T,U>
函数两次的——但它可以。因此,我不明白为什么它不能推断出vectpair
应该同时使用vector<T>
和pair<T,U>
函数?
这与为什么const
关键字会增加转换从而使T
功能更好有关吗?(但是在这种情况下,另外两个例子是如何工作的呢?(
是否只有在递归调用中首先测试当前函数的模板推导时,才有可能进行两个第一次推导?
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
template<class T> string print(const T& t){
ostringstream s;
s << t;
return s.str();
}
template<class T> string print(const vector<T>& t){
ostringstream s;
s << '[';
for(int i=0;i<(int)t.size();i++)
s << print(t[i]) << ' ';
s << ']';
return s.str();
}
template<class T,class U> string print(const pair<T,U>& t){
ostringstream s;
s << '(' << print(t.first) << ',' << print(t.second) << ')';
return s.str();
}
int main ( int argc, char **argv ) {
vector<vector<double> > vectvect(4,vector<double>(4));
for(int i=0;i<(int)4;i++)
for(int j=0;j<(int)4;j++)
vectvect[i][j] = i*4+j;
pair<int,pair<string,double> > pairpair = make_pair(10, make_pair("foo",0.5));
vector<pair<int,string> > vectpair(1,make_pair(42,"bar"));
///template deduction
cout << print(vectvect) << endl;
cout << print(pairpair) << endl;
///template deduction failure
//====> here is the problem
//cout << print(vectpair) << endl;
return 0;
}
目前,我只是想了解,但如果有人知道如何在不引入大量源代码开销的情况下做到这一点,我很感兴趣。
谢谢。
问题与模板参数推导无关,也与重载解决无关。采用一对的print
重载不会被编译器选中,因为它不能通过非限定名称查找找到,ADL也不能找到。您应该对函数的两个定义进行重新排序,以便取一对的定义优先:
template <class T,class U> string print(const pair<T,U>& t){
/**/
}
template <class T> string print(const vector<T>& t){
/**/
}
或者在定义和使用之前声明所有函数:
template <class T> string print(const T& t);
template <class T,class U> string print(const pair<T,U>& t);
template <class T> string print(const vector<T>& t);
您的问题是,当您试图打印vector<pair<X>>
时,这个带有vector
重载的调用:
s << print(t[i]) << ' ';
找不到pair<T,U>
重载,因为不合格查找发生在定义点,而不是以后。因此,它调用您的通用print(const T&)
并不是因为模板排序规则中的一些中断,而是因为pair<T, U>
重载根本不可见。
如果我能用Leeroy Jenkins的声音说Argument Dependent Lookup就好了。那太棒了。不管怎样,ADL最酷的地方是查找发生在之后。因此,您不必担心确保所有功能都是预定义的。只要多加一个论点,让ADL来做它的事情。在顶层,我们只是向前推进:
template <typename T>
string print(T const& val)
{
return print(adl::helper{}, val);
}
然后我们在namespace adl
:中定义了所有相同的print
函数
namespace adl {
struct helper{};
template<class A, class T> string print(A, const T& t){
ostringstream s;
s << t;
return s.str();
}
template<class A, class T> string print(A, const vector<T>& t){
ostringstream s;
s << '[';
for(int i=0;i<(int)t.size();i++)
s << print(helper{}, t[i]) << ' ';
s << ']';
return s.str();
}
template<class A, class T,class U> string print(A, const pair<T,U>& t){
ostringstream s;
s << '(' << print(helper{}, t.first) << ',' << print(helper{}, t.second) << ')';
return s.str();
}
}
任何地方都没有订购问题。现在我们甚至可以打印…的pair
的vector
的pair
的vector
。。。
- 继承函数的重载解析
- 你能重载对象变量名本身返回的内容吗
- 从父命名空间重载类型
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 重载操作程序时出错>>用于类中的字符串 memebr
- 此代码是否违反一个定义规则
- 一个关于在C++中重载布尔运算符的问题
- 函数重载中的规则
- 使用经典重载解析规则创建依赖于 std::调用的重载集类
- 了解方法重载规则
- 标识符规则是否适用于运算符重载函数
- 运算符重载中的作用域规则
- 在类中使用'const'和在C++中使用运算符重载是否有一个好的规则?
- 误解全局运算符重载规则
- 为什么存在 C++11 std::initializer_list 构造函数重载规则
- 重载解决规则C++缺陷
- C++中继承的重载规则
- c++中重载递归函数的模板推导规则
- C++名称解析(和重载)规则列表