为什么模板函数没有应用自动向下转换?

7

有人问了这个问题,关于字符串拼接。代码string s; s = s + 2;无法编译通过。人们给出的答案说明operator+是一个模板函数,而operator+=不是,所以自动下转换(int(2)char(2))没有被应用。

函数原型如下

template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string{
    basic_string&
      operator+=(_CharT __c);
};

template<typename _CharT, typename _Traits, typename _Alloc>
  inline basic_string<_CharT, _Traits, _Alloc>
  operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs, _CharT __rhs);

为什么编译器不能只使用这个原型,并将int(2)强制转换为char(2)?
basic_string<char, _T, _A> operator+(const basic_string<char, _T, _A>, char);

编译器(G++ 6.3.0)报错,提示
[Note] deduced conflicting types for parameter '_CharT' ('char' and 'int')

2
编译器推断模板类型时的规则是,不考虑转换;类型必须完全匹配。虽然在某些情况下,转换可能会方便明了,但总体而言,可能性太多了,编译器不需要搜索每种可能的类型,以寻找能够转换为与模板参数列表的部分相匹配的内容。 - Pete Becker
可能是这样,但实际上并不是。这样做需要为basic_string所支持的所有标准类型专门定制模板。另外,string s; s = s + 2;没有太多意义。你想要值为2的ASCII字符还是想要'2'?我看不出为什么你需要你的版本。 - NathanOliver
@PeteBecker 很好的回答。你能否把它发布出来,而不是留在评论里? - iBug
@NathanOliver 我想要实现与 '\x02' 相同的效果,值是从我提到的那个问题中借用的。 - iBug
1个回答

8
关键区别在于,对于operator +=变体,std::basic_string的char类型模板参数(因此是其RHS的参数类型)已经固定为char,而operator+模板需要从其参数中推断出该值。

因此,在+=情况下,编译器知道你“想要”int->char转换,没有什么需要推断的。
另一方面,在operator+情况下,编译器正在查看模板。
template<class CharT, class Traits, class Alloc>
    basic_string<CharT,Traits,Alloc>
        operator+( const basic_string<CharT,Traits,Alloc>& lhs,
                   CharT rhs );

当尝试确定CharT应该是什么时,它从第一个操作数中获取CharT = char(因为std::stringstd::basic_string<char>),并从第二个操作数中获取CharT = int。标准规定这种冲突会导致编译错误。


点赞。这比我在链接问题中的答案要好得多,需要投票跟上。(作为锦上添花,您可能想提到CharTchar之间的关系。) - Bathsheba
@Bathsheba 谢谢,已添加。不过我觉得赶上可能不太可能了,毕竟这个答案已经太老了。XD - Baum mit Augen
让我总结一下:如果数据用于类型推断,那么它不能被隐式转换。 - iBug
那么你的意思是因为在我想要发生隐式转换的时候,目标类型还没有确定,所以没有什么可以转换的吗? - iBug
1
@iBug 但请注意,目标类型根本无法确定,而不是尚未确定。 - Baum mit Augen
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接