2011-04-28 53 views
2

昨天我看到了一些有趣的编译器行为,我想我理解它为什么会发生,但我想确定。所以,我不会写我的推理,只是事实。使用模板:首先解析运算符还是首先解析转换?

请注意,这不是我输入的错别字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 +' 

因此,编译器四处搜索+意味着什么,并抱怨说它无法推断出适当的模板参数。我惊讶于两件相关的事情,其中一个是它为每个涉及模板的超载+运算符提供此错误。这告诉我,编译器绝对没有办法排除这些+中的任何一个都没有意义; 两个,这是相关的,它不只是抱怨没有合适的运营商存在。

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

+1

哦,并且只是为了编译器甚至知道'std :: basic_string <...>'的评论。它包含在''通过''通过''。 :) – Xeo 2011-04-28 17:16:14

+0

+1这很有趣。我也想知道。 – 2011-04-28 17:16:52

回答

2

事实上,由于找不到匹配项,它使用错误来告诉您其实际找到的可能的运算符候选项。

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

它这样做是为了帮助:因为它找不到匹配项,所以假设您可能实际上意味着任何可能的可用操作符。

+0

有几个人回答,但是这是第一位的。谢谢。 – 2011-04-28 17:28:59

1

它不只是抱怨没有合适的操作符存在。

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

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

一般情况下,它不能做到这一点,因为例如std::_Vector_iterator<_Ty,_Alloc>可能是一个基类的std::basic_string<>,这意味着一个操作符重载可能是可行的,扣得手。参数推导是编译C++的阶段,它将这些事情计算出来,而编译器只是向您报告推论推论的结果。

+1

VC10确实报告没有合适的运算符存在('错误C2676:binary'+':'std :: string'未定义此运算符或转换为预定义运算符可接受的类型)。它被报告在所考虑的过载列表的末尾,而不是之前,但至少有报道。 (我不知道OP的编译器VC8是否也这样做了;我没有安装任何地方检查。) – 2011-04-28 17:20:04

+0

@James ohh谢谢检查! – 2011-04-28 17:22:20

+0

的确如此:James:'1>。\ test.cpp(21):error C2676:binary'+':'std :: basic_string <_Elem,_Traits,_Ax>'没有定义这个运算符或者是一个类型的转换预定义的操作员可以接受“因为有37个错误,所以我没有那么做。 – 2011-04-28 17:44:04

2

注意,这并不是说我已经包括vector,而不是string一个错字。我故意这样做,以便编译器无法理解std :: string是什么,所以它将不得不四处搜索以找出+指的是哪个运算符。

这是不正确的。编译器确实知道std::string是什么。举个例子,下列程序编译就好了(使用Visual C++ 2010,但它也应该在2005年的工作):++ 2005年至2010年

#include <vector> 

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

当使用Visual C++(至少的Visual C,我可以” t代表其他版本),包括<vector>也包括任何内部头部声明并定义std::basic_stringstd::string。这是C++语言标准所允许的。

但是,您显然没有得到std::string(或更准确地说,std::basic_string)操作数的operator+过载。为了得到那些你必须包括<string>

编译器完全知道什么是std::string,但是当它试图找到一个operator+过载两个std::string对象,它失败并报告所有的operator+重载,它认为,但被拒绝。

+0

+1,谢谢。关键点似乎在你的最后一段。也就是说,如果它只能找到'operator +'的模板版本,那么它会产生所有无法找到转换的内容,并且这是故意做到的。然而,看起来如果'operator +'有非模板重载,那么它只会抱怨一次。毕竟,我想这是一个功能。 – 2011-04-28 17:28:18

+0

你的回答节省了我的时间。MS糟糕的文件记录(IMO)的其中一件事正是其中包括用于给定的一类或一组功能。我正在重复使用代码,并不知道我需要 ...毕竟我已经有。非常感谢! – ChronoFish 2012-12-14 03:05:23

+0

@ChronoFish:''和''是两个不同的标题:前者来自C标准库;后者来自C++标准库。除了相似的名字,它们完全不相关。哪些标题包含哪些其他标题基本上未指定。程序员需要包含正确的头文件。例如,您可以从许多地方之一找出您需要包含哪个标头 - [cppreference.com](http://en.cppreference.com/w/)。 MSDN也应该有这个文档。 – 2012-12-14 03:26:50