C++大括号初始值设定项作为参数调用不同的构造函数,然后预期



最小的例子是这样的类:

class Chain {
public:
Chain(std::string name, std::vector<int> args)
{
assert(true);
}
Chain(std::string name, bool flag)
{
assert(false);
}
};

用法如下

int main() {
auto ch = Chain("name", {});
return 1;
}

Chain的第二个构造函数以前没有bool flag,我必须添加它,现在代码Chain("name", {})调用第二个构造函数(在它调用第一个构造函数之前(。

我想我会改变第二个构造函数的参数顺序

Chain(bool flag, std::string name)
{
assert(false);
}

但即便如此,它也会将const char *强制转换为bool{}强制转换为std::string然后调用第一个构造函数。

有没有办法禁止它/强制使用调用第一个 ctor?

使用显式类型。

auto ch1 = Chain("name", std::vector<int>{});
auto ch2 = Chain("name", true);

重载解析规则很复杂:

以下任何重载都是可行的:

Chain(std::string name, std::vector<int> args); #1
Chain(std::string name, bool flag); #2a
Chain(bool flag, std::string name); #2b

Chain("name", {});

#2a#2b都是比#1最好的候选人,特别是因为:

1( 标准转换序列总是优于用户定义的转换序列或省略号转换序列。

所以{} -> bool{} -> std::vector<int>好,
const char* -> boolconst char* -> std::string
好({} -> std::vector<int>相当于{} -> std::string(。

我建议在bool周围添加一个包装类,如下所示:

struct bool_wrapper
{
// bool_wrapper() : b(false) {} // would make your call ambiguous.
bool_wrapper(bool b) : b(b) {}
operator bool() const {return b;}
bool b = false;  
};

然后

Chain(std::string name, bool_wrapper flag); // To fix overload resolution

演示
演示与模棱两可的调用

如果您不能像Chain("name", std::vector<int>{});那样修改对第一个构造函数的调用,我可以建议两种方法。

如果对第一个构造函数的调用始终使用字符串文本(如"name"(不是 std::string(执行,则可以修改这两个构造函数:

class Chain {
public:
Chain(const char* name, std::vector<int> args)
{
assert(true);
}
Chain(bool flag, const std::string& name)
{
assert(false);
}
};

如果上述假设为 false,则可以将虚拟参数添加到第二个构造函数中:

class Chain {
public:
Chain(std::string name, std::vector<int> args)
{
assert(true);
}
Chain(std::string name, bool flag, bool dummy)
{
assert(false);
}
};

以及不需要修改构造函数的奖励解决方案:

class Chain {
public:
Chain(const std::string& name, std::vector<int> args)
{
assert(true);
}
template<typename T>
Chain(const std::string& name, T flag);
};
template<>
Chain::Chain(const std::string& name, bool flag)
{
assert(false);
}

最新更新