C ++在操作数中对标准运算符的隐式转换

时间:2016-12-02 22:20:07

标签: c++ visual-c++ operators implicit-conversion

我在理解C ++使用隐式转换的条件时遇到了一些麻烦。假设我有一个班级:

class SomeClass
{
private:
    int val;
public:
    SomeClass(int i) :val{ i } {}
    operator string() { return to_string(val); }
};

为什么在将这个类与运算符一起使用时我需要转换为字符串?为什么它不会隐含地执行转换?

代码:

int main(void)
{
    SomeClass sc = 4;
    cout << (string)sc << endl; //prints 4, compiles fine
    cout << sc << endl;//does not compile, no operator "<<" matches these operands

    string str1 = sc;//compiles fine, performs cast
    string str2 = "Base String" + sc;//does not compile, no operator "+" matches these operands
}

这个问题更具学术性而非实际性,因为使用演员表无论如何都更具可读性。

2 个答案:

答案 0 :(得分:2)

std::cout不接受std::string 它接受一个模板std::basic_string,其参数将被推导出来 有关详细信息,请参阅here

让我们考虑以下示例:

#include<string>

struct SomeClass {
    operator std::string() { return ""; }
};

template <class CharT, class Traits, class Allocator>
void f(const std::basic_string<CharT, Traits, Allocator> &) {}

template <class CharT, class Traits, class Allocator>
void f(std::basic_string<CharT, Traits, Allocator> &) {}

int main(void) {
    SomeClass sc{};
    f((std::string)sc);
    //f(sc);
}

它类似于你的情况 当然,f(sc)不会因为几乎相同的原因而编译。

问题是,推导出模板参数SomeClass应该转换为std::string。为了能够将其转换为std::string,编译器应该猜测存在有效的重载并尝试使用它。无论如何,从它的角度来看,这样一个可行的函数是不存在的,因为仍然需要推导出模板参数并推导它们,编译器应该猜测在转换后存在SomeClass的重载。它不能,因为......等等。

我没有检查过,但我敢打赌类似的东西也适用于operator+

答案 1 :(得分:2)

编写cout << (string)sc时使用的operator<< overload是一个函数模板:

template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
    operator<<(std::basic_ostream<CharT, Traits>& os,
               const std::basic_string<CharT, Traits, Allocator>& str);

这是因为std::string本身就是一个类模板,并且可以使用除char之外的其他类型进行实例化,并且如果将字符写入相同字符类型的流,则仍然可以打印。事实上,std::wstring恰好发生了什么,其中CharTwchar_t而不是char。如果你使用合适的流,那同样的operator<<也可以。

当您编写cout << sc时,会考虑该特定的重载。然后拒绝该重载,因为编译器无法推断出CharT和其他类型使用哪种类型。如果它已经知道转换将被执行,它只能推断出类型,但转换不仅仅被考虑,它们只会在稍后阶段进行检查。

如果有operator<<的非模板std::string重载,那么它会起作用,sc会被隐式转换。