使用模板:首先解析运算符或首先解析转换?

时间:2011-04-28 17:05:40

标签: c++ templates compiler-construction compiler-errors

我昨天看到了一些有趣的编译器行为,我想我明白为什么会这样,但我想确定。所以,我不会写出我的推理,只是事实。

请注意,这不是我所包含的vector而非string 的拼写错误。我故意这样做,以便编译器无法理解std :: string是什么,因此它必须搜索以找出+所指的运算符:

#include <vector>
// #include <string> // intentionally commented out

template <typename T> struct A
{
    A() { };
    ~A() { };

    int m_member;
};

template <typename T> A<T> operator+(double lhs, const A<T> &rhs);

int main(int argc, char **argv)
{
    std::string fullString = std::string("Hi ") + std::string("mom!");
}

因此,我在MS Visual Studio 2005中遇到了大量的编译器错误。我只展示了它们的一部分。

1>.\test.cpp(21) : error C2784: 'A<T> operator +(double,const A<T> &)' : could not deduce template argument for 'const A<T> &' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        .\test.cpp(16) : see declaration of 'operator +'

......错误继续......

1>.\test.cpp(21) : error C2784: 'std::_Vb_iterator<_MycontTy> std::operator +(_Vb_iterator<_MycontTy>::difference_type,std::_Vb_iterator<_MycontTy>)' : could not deduce template argument for 'std::_Vb_iterator<_MycontTy>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(1800) : see declaration of 'std::operator +'

......错误继续......

1>.\test.cpp(21) : error C2784: 'std::_Vb_const_iterator<_MycontTy> std::operator +(_Vb_const_iterator<_MycontTy>::difference_type,std::_Vb_const_iterator<_MycontTy>)' : could not deduce template argument for 'std::_Vb_const_iterator<_MycontTy>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(1695) : see declaration of 'std::operator +'

......错误继续......

1>.\test.cpp(21) : error C2784: 'std::_Vector_iterator<_Ty,_Alloc> std::operator +(_Vector_iterator<_Ty,_Alloc>::difference_type,std::_Vector_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_iterator<_Ty,_Alloc>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(396) : see declaration of 'std::operator +'

......错误继续......

1>.\test.cpp(21) : error C2784: 'std::_Vector_const_iterator<_Ty,_Alloc> std::operator +(_Vector_const_iterator<_Ty,_Alloc>::difference_type,std::_Vector_const_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_const_iterator<_Ty,_Alloc>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(264) : see declaration of 'std::operator +'

因此,编译器会搜索+的含义并抱怨它无法推断出适当的模板参数。我对两个相关的事情感到惊讶,一个是它为每个涉及模板的重载+运算符提供此错误。这告诉我,编译器完全没有办法排除这些+中的任何一个都没有意义; 两个,这是相关的,它不仅仅抱怨没有合适的运营商。

我认为这是一个了解模板如何实例化和编译的机会。有没有人有任何好的解释或参考?

3 个答案:

答案 0 :(得分:2)

事实上,由于无法找到匹配项,因此使用错误告诉您实际找到的可能的运算符候选项。

例如,g ++错误告诉你它找不到运算符然后提供相同的消息,但是在“候选者是:”形式而不是每个运算符一个错误。

这样做是为了帮助:由于无法找到匹配项,因此假定您实际上可能意味着任何可能的运算符。

答案 1 :(得分:2)

  

请注意,这不是我所包含的vector而非string 的拼写错误。我故意这样做,以便编译器无法理解std :: string是什么,因此它必须搜索+来指出我所指的是哪个运算符。

这不正确。编译器 知道std::string是什么。例如,考虑以下程序编译得很好(使用Visual C ++ 2010,但它也应该在2005年工作):

#include <vector>

int main() {
    std::string s;
}

使用Visual C ++时(至少是Visual C ++ 2005到2010;我不能代表其他版本),包括<vector>也包括任何内部头部声明并定义std::basic_string和{{1} }。这是C ++ langauge标准所允许的。

但是,您显然没有获得std::string(或更准确地说,operator+)操作数的std::string重载。要获得那些,您必须包含std::basic_string

编译器完全清楚<string>是什么,但是当它试图为两个std::string对象找到operator+重载时,它会失败并报告所有std::string它考虑但是被拒绝的重载。

答案 2 :(得分:1)

  

它并不只是抱怨没有合适的运营商。

这就是IMO一个简单的愚蠢的编译器行为,如果发生了这种情况。当然它应该首先告诉你什么是错的(即没有合适的运算符存在),然后列出所有考虑的模板。

  

一个是它为每个涉及模板的重载+运算符提供此错误。这告诉我编译器完全没有办法排除任何这些+没有意义;

通常,它不能这样做,因为例如std::_Vector_iterator<_Ty,_Alloc>可能是std::basic_string<>的基类,这意味着一个运算符重载可能是可行的并且演绎成功。参数推导是在那个阶段编译C ++的阶段,它将这些事情计算出来,编译器只会向你报告参数推导的结果。