class foo {
public:
explicit foo(int) { std::cout<<"int constructor"; }
};
int main() {
foo f(0.1);
return 0;
}
我认为显式关键字用于防止不需要的类型转换,但上面的代码仍可正常工作并输出&#34; int constructor&#34;。为什么?在这种情况下如何防止这种情况?
答案 0 :(得分:2)
你在这里混淆了一些概念。
explicit
阻止隐式构造函数调用,而不是使用隐式参数类型转换的构造函数调用。
不幸的是,解决方案并不简单。它不是新手友好的,可能需要一些谷歌搜索才能理解。
你可以显式删除浮点类型的构造函数:foo(float) = delete;
等等。然后foo f(0.1);
将导致'使用已删除的函数'错误。 但是你也无法做foo f(1l)
,编译器会抱怨'模糊的重载'。
正确的方法如下:
class foo
{
public:
foo(int) {std::cout << "int constructor\n";}
template <typename T,
typename = std::enable_if_t<std::is_floating_point_v<T>>>
foo(T) = delete;
};
它类似于删除每个浮点类型的重载(如上所述),但由于SFINAE,对于非浮点类型,不会考虑删除的重载。
答案 1 :(得分:0)
关键字explicit
会将消息强制为conversion from ‘int’ to non-scalar type ‘foo’ requested
,从而强制执行编译时错误:foo f = 1;
。这是他们所期望的一切。
为什么允许浮点值0.1
被回答here。
此外,如果您想要阻止此行为,请使用以下代码行:
foo(double) = delete;
然后在传递float / double值时会收到错误:use of deleted function ‘foo::foo(double)’
。
答案 2 :(得分:0)
显式构造函数阻止从构造函数采用的类型隐式转换为您的类型。所以在这种情况下,它会阻止从int
隐式转换为foo。所以:
foo f = 1;
不会编译。但是,这是明确的结构:
foo f(1);
这当然会奏效。在您的情况下,您传递了一个double而不是int。但是,在语言中内置了从double到int的隐式转换,这就是它编译的原因。换句话说,你的问题是这个编译:
int x = 0.1;
然而,在gcc上编译-Wconversion
(我相信clang)会对此发出警告,如果你正在编译-Werror
(你应该),它会把它变成一个编译错误。我怀疑如果您正在使用该编译器,MSVC会出现类似的错误。