防止 bool 中的隐式对象构造?

Prevent implict object construction from bool?

我有一个class、X,它有以下构造函数:

class X{

    X(int64_t, int16_t, bool, int8_t);
    X(int64_t, int16_t, bool);
    X(double);
    X(double, FT);

    explicit X(const string&); 
    X(const string&, Y);
};

问题是编译器曾经创建了一个只传递一个布尔值的 X 对象(假设它是允许这个的双构造函数?)并且它导致了一个问题。

为了防止这种情况,我将 bool 构造函数显式化并删除了它:

explicit X(bool) = delete;

但现在我收到编译器错误:

EXPECT_EQUALS(X("9.8901099"), a/b);
EXPECT_EQUALS(X{"56267"}, x);
X x{"-56267E-1"};
X b("5");

编译器说我使用了删除的函数explicit X(bool) = delete

如何防止从布尔创建 X 的对象?

发生这种情况是因为 boolstd::string 更适合 const char[]。当你没有接受 bool 的 ctor 时,就会选择 std::string 一个。当你有一个带 bool 的构造函数时,就会选择这个重载。只是删除了所以调用是非法的

让我们用一个简单的自由重载函数看看这个行为:

auto foo(int) { cout << "foo int" << endl; }
auto foo(std::string const &) { cout << "foo string" << endl; }

auto main() -> int {
  foo(3);       // int
  foo("Asdf");  // std::string
}

添加 bool 重载时:

auto foo(int) { cout << "foo int" << endl; }
auto foo(std::string const &) { cout << "foo string" << endl; }
auto foo(bool) { cout << "foo bool" << endl; }

auto main() -> int {
  foo(3);      // int
  foo("Asdf"); // bool (also warning implicit conversion turn string literal into bool)
}

解决方法是添加一个char const *重载:

auto foo(int) { cout << "foo int" << endl; }
auto foo(std::string const &) { cout << "foo string" << endl; }
auto foo(char const *s) {
   cout << "foo char const *" << endl;
   // possibly:
   return foo(std::string{s});
}
auto foo(bool) = delete;

auto main() -> int {
  foo(3);      // int
  foo("Asdf"); // char const *
  foo(true);   // error
}

因为一些遗留代码使用 returns char * 而不是 char const * 你可能还需要添加一个 char * 重载。

首先,您需要了解如果显式删除 bool 构造函数会发生什么。它在重载 selection 中变得可用,当它是最佳匹配时,它就会被使用,然后给出一个编译器错误,因为它被删除了。

这与您未定义它时不同,因为您确实可以 'stop' 通过隐式转换转换的布尔值加上后跟 class [的(不同的)构造函数=12=],因为它是布尔值的最佳匹配,所以隐式转换到此为止。

考虑您的 class

的用途
X x("abc");

没有删除的 bool 构造函数,这个 selects X(const string&).

然而,使用删除的 bool 构造函数,这将 select 和 explicit X(bool),后者也被删除,因此会产生编译器错误。正如 Kerrek SB 所说,解决这个问题的方法是也为 const char * 定义一个构造函数。

确实,如果您不删除 bool 构造函数,那么下面的 select 就是 double

X x(true);

首先转换为 int,然后转换为 double

因此,您可以选择删除或不删除的解决方案,但您需要了解后果和要求。如果删除它,则需要提供一个 const char * 构造函数。如果您不删除它,那么您需要接受 bool 可用于构建 class.

的实例这一事实