How to differentiate implicit/explicit constructor calls in C++?

337 views Asked by At

I'm trying to detect when an explicit constructor call has been called vs. an implicit one.

Suppose we have a class Foo:

class Foo{
public:
    Foo(int _val) : val(_val){};
private:
    int val;
}

void bar(Foo f){
   ...
}

We can call bar like:

Foo f(10);
bar(f);

or like:

bar(10); // implicit initialization

Now, I am aware that if we make the ctor explicit:

class Foo{
public:
    explicit Foo(int _val) : val(_val){};
private:
    int val;
}

Then we can get this error:

bar(10); // ERROR! implicit initialization not allowed.

So I thought perhaps there could be a workaround to detect an explicit call vs. implicit, like this:

class Foo{
public:
    explicit Foo(int _val) : val(_val){}; // calling Foo f(10); bar(f);
    Foo(int _val) : val(_val){}; // calling bar(10);
private:
    int val;
}

But as expected, it returns "cannot be overloaded", as the function signatures are ambiguous.

The end result should be something like:

class Foo{
public:
    explicit Foo(int _val) : val(_val), flag(true) {}; // calling Foo f(10); bar(f);
    Foo(int _val) : val(_val), flag(false) {}; // calling bar(10);
private:
    int val;
    bool flag;
}

void bar(Foo f){
    std::cout << "f's flag set to : " << f.flag << std::endl;
}

Foo f(10);
bar(f); // f's flag set to : 1
bar(10); // f's flag set to : 0

But obviously since the above attempt was futile, and I don't have a better idea, I was wondering if it is even possible to do this in C++. If it's not, then it's fine.

3

There are 3 answers

0
R Sahu On BEST ANSWER

So I thought perhaps there could be a workaround to detect an explicit call vs. implicit, like this:

No, it's not possible. If this is purely out of curiosity, then you have your answer. If there is a real problem you are trying overcome, you may want to post the real problem.

1
gsamaras On

it is even possible to do this in C++?

No.

As you saw the overloading ambiquitity is an issue, which makes it impossible for you to know whether the implicit constructor was called or the explicit one.

One may assume that in your case it would be possible to know which constructor was called, by keeping an eye out for the copy needed by the explicit constructor (in contrast with the implicit one), but this is not that much reliable, since a good compiler can take advantage of Copy Elision and bypass the copy operation.

So if we would rely on that copy assumption by us to determine whether the explicit constructor was called or not, we could be receive a false negative, in case the copy was actually elided.

In general, copy constructors are allowed to be elided, they should not have side effects.

12
Pete Becker On

It's easy, but the solution is in the function being called, not in the object that you're creating.

void bar(Foo&) { ... }
void bar(Foo&&) { ... }

Foo f(10);
bar(f);  // calls the first one
bar(10); // calls the second one