使用显式构造函数

时间:2017-08-25 17:34:28

标签: c++ constructor explicit

class foo {
public:
    explicit foo(int) { std::cout<<"int constructor"; }
}; 

int main() {
    foo f(0.1);
    return 0;
}

我认为显式关键字用于防止不需要的类型转换,但上面的代码仍可正常工作并输出&#34; int constructor&#34;。为什么?在这种情况下如何防止这种情况?

3 个答案:

答案 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会出现类似的错误。