为什么只能在一种情况下推导模板参数?

时间:2012-08-06 08:44:52

标签: c++ stl

为什么以下代码使用非const迭代器为该行编译,但 const iterator (使用Visual Studio 2008)失败?

#include <vector>

using std::vector;

int main(int argc, char* argv[])
{
    vector<int> test;

    test.push_back(1);
    test.push_back(2);

    vector<int>::const_iterator cit = test.end();
    std::distance(test.begin(), cit); // error: template parameter is ambiguous

    vector<int>::iterator it = test.end();
    std::distance(test.begin(), it);

    return 0;
}

注意:在Visual Studio 2008中,没有矢量成员函数cbegin()来避免模糊,但是重载begin()方法:

iterator begin()
    {   // return iterator for beginning of mutable sequence
    return (iterator(_Myfirst, this));
    }

const_iterator begin() const
    {   // return iterator for beginning of nonmutable sequence
    return (const_iterator(_Myfirst, this));
    }

4 个答案:

答案 0 :(得分:2)

模板distance只接受一个参数distance<T>(T first, T last)。由于test.begin()的类型为iteratorcit的类型为const_iterator,因此无法推断出模板参数。

您可以使用test.cbegin()来获得有保证的const_iterator,或者说static_cast<std::vector<int> const &>(test).begin()

(这与你max<T>(T x, T y)并试图说max(1, 2U)一样 - 它不会编译,因为它不明确。)

答案 1 :(得分:1)

  

注意:在Visual Studio 2008中,没有矢量成员函数cbegin()来避免模糊,但是重载begin()方法:

我认为编译器总是选择非const对象的非const重载,而const方法只选择const对象。

调用

std::distance(test.begin(), cit);

查看begin的重载集和cit的类型,并确定它是否可以匹配。它首先解决了过载(到了非const版本),因此失败了。

表达你的意图的最简洁的方法也可能适用于编译器:

vector<int> const &cref = test;
vector<int>::const_iterator cit = cref.end();
std::distance(cref.begin(), cit);

答案 2 :(得分:0)

功能模板std::distance只需一个模板 参数,对于两个函数参数必须相同。该 返回类型test.begin()只是iterator,而不是const_iterator std::vector<int>::iterator,因此函数参数的类型不同。 编译器为第一个推导出std::vector<int>::const_iterator,并且 cbegin为第二个,所以扣除 失败。模板参数推断会考虑到 可能的转换,除了最简单的转换。

有许多方法可以解决问题,但它们都很明显 缺点。 (这可能是委员会添加cend和。{ const函数。)目前,您最好的选择可能就是放弃iterator,并使用{{1}}。

答案 3 :(得分:0)

distance必须同时具有模板参数。在这种情况下,它是_Vector_const_iteratorbegin有两个重载:const和非const。 const-version生成_Vector_const_iterator,但另一个生成_Vector_iterator_Vector_iterator继承自_Vector_const_iterator

因此,begin的const和非const重载都能够生成_Vector_const_iterator,并且它们都可以被选为非const对象,即编译器会混淆。

这就是我编译的方式:

    std::distance(((const vector<int>&)test).begin(), cit);