我有一个类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对象?
答案 0 :(得分:2)
这是因为bool
与const 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
可用于构建你的类实例的事实。