通过传递构造函数参数在函数参数中自动构建对象

Automatic Object Construction in Function Parameters by Passing Constructor Parameters

你能解释一下为什么下面的代码可以编译运行吗?这里的概念是什么,这种方法起作用的 limitations/requirements 是什么?

class string_wrapper
{
public:
    string_wrapper(string i_string);

    string m_value;
    int m_length;
};

string_wrapper::string_wrapper(string i_string)
{
    m_value = i_string;
    m_length = i_string.length();
}

void bar(string_wrapper i_param)
{
    cout << i_param.m_value << std::endl;
}

void foo()
{
    string test_string = "test1";

    bar(test_string);
}

int main()
{
    test_function_b();
}

输出:

test1

我希望这段代码无法编译。 foo() 将字符串参数传递给 bar(),而 bar 仅采用 string_wrapper 参数。然而,编译器足够聪明,知道它可以将字符串参数用作 string_parameter 对象的构造函数的参数,然后可能将其作为实际参数传递给 bar().

此行为是 C++ 标准中的行为,还是我的编译器独有的行为(Visual Studio 2017,版本 15.9,在本例中)?任何我可以用于进一步研究的见解或术语将不胜感激。

这里发生的是隐式构造。你说得对,编译器 'smart' 足以知道你可以从 std::string 中创建一个 string_wrapper,因此它会自动为你创建。

要阻止这种情况发生,您可以像这样使用 explcit 关键字:

...
explicit string_wrapper(string i_string);
...

explicit 关键字告诉编译器您不希望它自动从 std::string 中为您构造 string_wrapper 个对象。这可以阻止很难追踪错误,因为它可以防止意外构造对象(尤其是在函数 returns 和传递参数时)。

当一个对象只有一个非默认参数时,可能会发生隐式构造(隐式转换也是您应该研究的东西)。它可以是一个强大的工具,可以允许诸如代理 classes 和透明 API(即 std::vector 的引用 class)之类的东西。通常,您应该声明单个参数(或单个未默认值)构造函数(和转换运算符)explicit,除非您做出的设计决定也不是。