c ++中重载递归函数的模板推导规则

时间:2015-09-30 19:45:55

标签: c++ templates recursion overloading

我发现了很多关于模板推导的信息(例如C++ templated function overloading rules),但它无法帮助我理解重载递归函数的模板推导行为。 在下面的代码中,我并不真正理解编译器如何设法推断它应该vector<T>两次使用vectvect函数而pair<T,U>使用pairpair两次vector<T> - 但它可以。 因此,我不明白为什么它不能推断它应该pair<T,U>使用vectpairconst函数?

这与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

目前,我只是想了解,但如果有人知道如何在不引入大量源代码的情况下做到这一点,我感兴趣。

谢谢。

2 个答案:

答案 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 vectorpair ...