当在类中声明运算符std :: string时,运算符bool()如何导致错误,并且还可以作为字符串的隐式转换?
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
operator std::string() { cout << "op string" << endl; return "whatever";}
operator bool() { cout << "op bool" << endl; return true;}
};
int main(int argc, char *argv[]) {
string s;
Test t;
s = t;
}
答案 0 :(得分:8)
您面临的问题(除了operator std::string()
返回bool之外)是隐式转换会在您需要时触发,何时不触发。
当编译器看到s = t
时,它会识别以下潜在的std::operator=
匹配:
// using std::string for compactness instead of the full template
std::string::operator=( std::string const & );
std::string::operator=( char );
现在,t
既不是它们,所以它会尝试将转换为适合的东西,并找到两条路径:转换为可以提升为{{1}的bool或直接转换为char
。编译器无法真正决定和放弃。
这是您希望避免提供许多不同转换运算符的原因之一。当您认为不应该被编译器隐式调用的任何东西时都会被调用。
此article专门处理此问题。建议不是提供转换为std::string
,而是提供对成员函数的转换
bool
如果在条件(class testable {
typedef void (testable::*bool_type)();
void auxiliar_function_for_true_value() {}
public:
operator bool_type() const {
return condition() ? &testable::auxiliar_function_for_true_value : 0;
}
bool condition() const;
};
)内使用此类的实例,编译器将尝试转换为可在条件中使用的if (testable())
。
修改强>:
在对此解决方案的代码更复杂的评论之后,您始终可以将其作为通用的小实用程序提供。提供代码的第一部分后,复杂性将封装在标题中。
bool_type
您的课程现在变得更加简单,并且它本身是可读的(通过为函数和类型选择适当的名称):
// utility header safe_bool.hpp
class safe_bool_t;
typedef void (safe_bool_t::*bool_type)();
inline bool_type safe_bool(bool);
class safe_bool_t {
void auxiliar_function_for_true_value() {}
friend bool_type safe_bool(bool);
};
inline bool_type safe_bool(bool)
{
return condition ? &safe_bool_t::auxiliar_function_for_true_value : 0;
}
只有当读者有兴趣知道如何实现// each class with conversion
class testable {
public:
operator bool_type() {
return safe_bool(true);
}
};
成语并读取标题时,他们才会面临复杂性(可以在评论中解释)
答案 1 :(得分:4)
你的运算符std :: string()需要返回一个字符串,而不是bool。
答案 2 :(得分:1)
正如大卫罗德里格斯正确指出的那样,bool
可以提升为char
而你会得到一个过度的超负荷。
在stl中,使类可测试通常是通过转换为void *
来完成的,例如当你做的时候
while (istream.getline()) {
}
循环条件解析为false,因为istream在其operator void*中返回NULL。
有些人认为这不是理论上可以做到的解决方案的好处
void* streamptr = istream;
delete streamptr;
但是在我看来,如果有人开始删除这样的指针......他不应该被允许在stl代码附近(或C ++)。