我发现了很多关于模板推导的信息(例如C++ templated function overloading rules),但它无法帮助我理解重载递归函数的模板推导行为。
在下面的代码中,我并不真正理解编译器如何设法推断它应该vector<T>
两次使用vectvect
函数而pair<T,U>
使用pairpair
两次vector<T>
- 但它可以。
因此,我不明白为什么它不能推断它应该pair<T,U>
使用vectpair
和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;
}
功能更好? (但是在这种情况下,另外两个例子如何起作用?)
这两个第一次推论是否可行,因为在递归调用中首先测试当前函数是否有模板推导?
VelocityTracker
目前,我只是想了解,但如果有人知道如何在不引入大量源代码的情况下做到这一点,我感兴趣。
谢谢。
答案 0 :(得分:2)
问题与模板参数推断无关,也不与重载决策有关。编译器不会选择成对的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);
答案 1 :(得分:1)
您的问题是,当您尝试打印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);
}
然后我们在print
中定义所有相同的namespace adl
函数:
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();
}
}
任何地方都没有订购问题。现在,我们甚至可以打印vector
pair
vector
个pair
...