Search code examples
c++functionparameter-passingfunction-parametercopy-initialization

Why copy intialisation is used instead of direct initialisation when passing argument to function parameter by value


I am learning C++ using the resources listed here. In particular, I came to know that copy initialization is used when passing arguments to function parameters(by value) etc.

For example, from decl.init.general#14:

The initialization that occurs in the = form of a brace-or-equal-initializer or condition ([stmt.select]), as well as in argument passing, function return, throwing an exception ([except.throw]), handling an exception ([except.handle]), and aggregate member initialization ([dcl.init.aggr]), is called copy-initialization.

(emphasis mine)

My question is that is there is reason for using copy initialization instead of direct initialization when passing argument to function parameters(by value)?


To make the question more concise, lets look at a contrived example:

struct C 
{
    explicit C(int)
    {
        
    }
};
void func(C param)
{
    
}

int main()
{
    C s1(2);  //#1: this works, direct-initialization and so explicit ctor can be used 
    C s2 = 2; //#2: won't work, copy-initialization and so explict ctor cannot be used here
    
    func(2);                  //#3:  won't work, copy-initialization of parameter param and so explict ctor cannot be used here
    return 0;
}

As we can see in the above example, the function call func(2) won't work because here the parameter param is copy initialized instead of direct initialized and so the explicit constructor C::C(int) cannot be used.

Summary

My question is why does the C++ standard(committee) choose to copy initialize the parameter param instead of direct initializing the parameter using the passed argument 2. I mean if param was direct initialized then the call func(2) would've succeeded.

Maybe there is a reason, like advantages of using copy initializing the parameter instead of direct initializing it or maybe there are disadvantages of using direct initializing the parameter instead of copy initializing it.


Solution

  • It is precisely so that this does not work.

    The whole point of the distinction between copy-initialization and direct-initialization is to prevent implicit conversions in cases of copy-initialization. By using explicit in your constructor, you are declaring that you do not want integers to be converted to C unless the user spells it out directly.

    When you attempt to call func(2), the type C is not explicitly visible anywhere near the call site. Therefore, it should be copy-initialization and if C's conversion constructor from int is explicit, the call should be disallowed.