防止bool的对象构造?

时间:2015-11-21 13:26:36

标签: c++ constructor compiler-construction

我有一个类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);
};

问题是编译器曾经创建过只传递一个bool的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

如何防止从bool创建X对象?

2 个答案:

答案 0 :(得分:2)

这是因为boolconst char[]的匹配比std::string更好。如果您没有ctor接受bool,则会选择std::string。当您拥有bool的ctor时,会选择此重载。只有它被删除所以调用它是违法的。

让我们通过简单的免费重载函数来看待这种行为:

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
}

由于某些遗留代码使用并返回char *而不是char const *,因此您可能还需要添加char *重载。

答案 1 :(得分:1)

首先,您需要了解如果明确删除bool构造函数会发生什么。它在过载选择中变得可用,当它被最佳匹配时,它会被使用,因为它被删除而给出编译器错误。

这与你没有定义它时的不同之处在于,你确实可以通过隐式转换加上后跟类X的(不同)构造函数来“停止”布尔值,因为它是布尔值的最佳匹配,因此隐式转换就在那里停止。

考虑你班级的用法

X x("abc");

如果没有已删除的bool构造函数,则会选择X(const string&)

但是,对于已删除的bool构造函数,这将选择explicit X(bool),它也会被删除,因此会产生编译错误。正如Kerrek SB所说,解决方案是为const char *定义一个构造函数。

事实上,如果您不删除bool构造函数,则以下选择double

X x(true);

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

因此,您可以选择解决方案,删除或不删除,但您需要了解后果和要求。如果删除它,则需要提供const char *构造函数。如果你不删除它,那么你需要考虑bool可用于构建你的类实例的事实。