显式错误类型的构造函数

时间:2016-09-20 16:09:37

标签: c++ c++11 constructor c++14

在下面的示例中,我的输出是"单个参数",两次。 我的问题是双重的,首先,为什么bool ctor调用而不是包含字符串的版本,第二,是否有办法在不转换调用的情况下调用字符串版本?

顺便说一句,我的实际代码并没有使用硬编码字符串调用构造函数,但是有类似的东西:

static constexpr auto NONE = "NONE";
Foo aFoo(NONE);

...

#include <iostream>
#include <string>

using namespace std;


struct Foo {

    explicit Foo(bool _isVisible = false): id(""), isVisible(_isVisible) {cout << "single param ctor" << endl;}
    explicit Foo(const string _id, bool _isVisible = false): id(_id), isVisible(_isVisible) {cout << "multip param ctor" << endl;}

    const string id;
    bool isVisible;
};

int main(int argc, const char * argv[]) {

    shared_ptr<Foo> sharedFoo = make_shared<Foo>("hello");
    Foo regFoo("hi");
    return 0;
}

2 个答案:

答案 0 :(得分:8)

这是继承自旧版C ++并最终来自C的C ++的限制。

您的字符串文字转换为bool优于“用户定义”类型std::string

您可以添加一个带const char*的构造函数,而不是在调用中强制转换,可能会将其委托给现有的构造函数std::string

explicit Foo(const char* _id, bool _isVisible = false)
   : Foo(std::string(_id), _isVisible)
{};

这个构造函数将是“完全匹配”(或者无论如何都足够接近),并阻止bool窃取风头。

或者,从C ++ 14开始,代替演员使用the std::string literal,例如"hi"s,虽然您必须记住在呼叫站点执行此操作,这对于一般解决方案来说有点“meh”。

顺便说一句,如果你真的想要按值std::string _id参数,请不要将其const;你阻止它被移动,并在成员初始化器中需要一个副本。根据典型呼叫站点的情况,以下内容可能更有意义:

explicit Foo(
   string _id,
   bool _isVisible = false
)
   : id(std::move(_id))
   , isVisible(_isVisible)
{}

但是,如果您通常传入左值,至少接受const std::string&以防止复制。

答案 1 :(得分:0)

  

为什么bool ctor调用而不是包含字符串的版本

因为"hi"一个指向char 的指针,一个字符数组被转换为指向char的指针(谢谢,Lightness Races in Orbit),所以我转换为一个数字布尔。

  

有一种方法可以在不转换调用的情况下调用字符串版本吗?

不是很优雅,但是......你可以传递第二个布尔参数

Foo regFoo("hi", false);

排除第一个构造函数