在下面的课程中,
您为什么要使运算符为explicit
。我以为explicit
是为了防止隐式调用构造函数?
class Content
{
public:
virtual ~Content() = 0;
virtual explicit operator float&();
virtual explicit operator long long&();
virtual explicit operator std::string&()
}
答案 0 :(得分:3)
我认为显式是为了防止隐式调用 构造函数?
自C ++ 11起,它也适用于user-defined conversions(又称 cast运算符)。
为什么要让运营商成为
explicit
在此上下文中使用的explicit
关键字使转换仅适用于直接初始化和显式转换。请参见[class.conv.fct¶2]下的此处:
在这种情况下,转换函数可能是显式的([dcl.fct.spec]) 仅被视为用户定义的转化 直接初始化([dcl.init])。否则,用户定义 转换不限于用于作业和 初始化。
这可以帮助您确保编译器不会尝试违反您的意图进行转换,因此您必须自己明确地进行转换,从而留出更少的错误空间。示例:
struct Foo
{
explicit operator int() {return 0;}
operator int*() {return nullptr;}
};
int main()
{
Foo foo;
//int xi = foo; // Error, conversion must be explicit
int i = static_cast<int>(foo); // OK, conversion is explicit
int* i_ptr = foo; // OK, implicit conversion to `int*` is allowed
int i_direct(foo); // OK, direct initialization allowed
int* i_ptr_direct(foo); // OK, direct initialization after implicit conversion
return 0;
}
在应用多个转换选项的情况下,它还可以帮助解决歧义,使编译器没有选择哪个选项的标准:
struct Bar
{
operator int() {return 1;}
operator char() {return '1';}
};
int main()
{
Bar bar;
//double d = bar; // Error, implicit conversion is ambiguous
return 0;
}
添加explicit
:
struct Bar
{
operator int() {return 1;}
explicit operator char() {return '1';}
};
int main()
{
Bar bar;
double d = bar; // OK, implicit conversion to `int` is the only option
return 0;
}
答案 1 :(得分:2)
请考虑以下内容:
struct Content
{
operator float() { return 42.f; }
friend Content operator+(Content& lhs, float) { return lhs; }
};
int main()
{
Content c{};
c + 0; // error: ambiguous overload for 'operator+'
}
在这里,编译器无法在operator+(Content&, float)
和operator+(float, int)
之间进行选择。使浮点运算符explicit
解决了这种歧义*:
c + 0; // operator+(Content&, float)
或
static_cast<float>(c) + 0; // operator+(float, int)
*),只要优先选择一个即可。
答案 2 :(得分:2)
其他答案涵盖了它的工作原理,但是我认为应该告诉您为什么将它添加到C ++中。
智能指针通常可以转换为bool
,因此您可以执行以下操作:
std::shared_ptr<int> foo;
if (foo) {
*foo = 7;
}
其中if(foo)
将foo
转换为bool
。不幸的是:
int x = foo+2;
将foo
转换为bool
,然后转换为int
,然后添加2
。这几乎总是一个错误。之所以允许这样做,是因为虽然只完成了一个用户定义的转换,但是在用户定义的转换之后进行的内置转换却可以静默进行。
要解决此问题,程序员会做疯狂的事情,例如添加:
struct secret {
void unused();
};
struct smart_ptr {
using secret_mem_ptr = void(secret::*)();
operator secret_mem_ptr() const { return 0; }
};
和secret_mem_ptr
是指向成员的秘密指针。指向成员的指针具有到bool
的内置转换,因此:
smart_ptr ptr;
if (!ptr) {
}
“有效”-ptr
转换为secret_mem_ptr
,然后将其转换为bool
,然后用于决定采用哪个分支。
这不仅仅是一个hack。
他们在转换运算符上添加了explicit
,以解决这个确切的问题。
现在:
struct smart_ptr {
explicit operator bool() const { return true; }
};
不允许:
smart_ptr ptr;
int x = 3 + ptr;
但它确实允许:
if (ptr) {
}
因为这些规则是手工制定的,以完全支持该用例。它还不允许:
bool test() {
smart_ptr ptr;
return ptr;
}
在这里,您必须输入:
bool test() {
smart_ptr ptr;
return (bool)ptr;
}
您将ptr
显式转换为bool
的地方。
(我通常真的反对C风格的强制转换;在(bool)
的情况下我是一个例外)。
答案 3 :(得分:1)
如果希望不要将Content
对象隐式转换为(例如)float
,则可以使用它。这可以通过以下方式发生:
void f( float f );
....
Content c;
f( c ); // conversion from Content to float
如果没有explicit
限定词,则转换将隐式进行;使用它,您会得到一个编译错误。
无声的,隐式的转换可能会引起许多混乱和/或错误,因此通常最好使运算符显式,或者可能最好提供诸如ToFloat
这样的命名函数,以告知操作者读者究竟是怎么回事。