Afshin
Afshin

Reputation: 9173

Is there anyway to disambiguate constructor selection?

I have a small code like this:

class A {
public:
    A() {
        std::cout << "ctor\n";
    }

    A(int i = 5) {
        std::cout << "ctor -> v\n";
    }

    virtual ~A() {
        std::cout << "dtor\n";
    }
};

int main() {
    A a;
}

It is is obvious that this code won't compile because A's constructor is ambiguous. I wonder if there is anyway to disambiguate this code by manually selecting which constructor to call. I don't want to pass default value in order to disambiguate function call (which is a obvious approach). I just want to know if there is any other way or not.

Upvotes: 4

Views: 570

Answers (3)

Without changing the constructor definitions there is no way in standard C++ to disambiguate the call.

Your options for clearing the ambiguity are to either remove the default argument, or to add a "dummy" tag argument to the first constructor.

constexpr struct default_tag_t{} default_tag{};
///
A(default_tag_t) {
    std::cout << "ctor\n";
}

Which makes the first constructor uniquely callable with

A a(default_tag);

Upvotes: 3

Samuel
Samuel

Reputation: 6490

Actually I think it is not possible. I was looking into getting to call the mangled name but I was not able to generate those mangled names. For this you have to expose the class to the binary interface by adding a __declspec(dllexport) and after you do this, even compiling the class is no longer possible (regardless of calling any ctor):

#include <iostream>
class __declspec(dllexport)  A {
public:
    A() {
        std::cout << "ctor\n";
    }

    A(int i = 5) {
        std::cout << "ctor -> v\n";
    }

    virtual ~A() {
        std::cout << "dtor\n";
    }
};

int main() {
   // A a;
}

Output was

1>------ Build started: Project: ConsoleApplicationMangled, Configuration: Debug Win32 ------
1>ConsoleApplicationMangled.cpp
1>e:\temp\ConsoleApplicationMangled\ConsoleApplicationMangled\ConsoleApplicationMangled.cpp(5,30): error C2668: 'A::A': ambiguous call to overloaded function
1>e:\temp\ConsoleApplicationMangled\ConsoleApplicationMangled\ConsoleApplicationMangled.cpp(11,5): message : could be 'A::A(int)'
1>e:\temp\ConsoleApplicationMangled\ConsoleApplicationMangled\ConsoleApplicationMangled.cpp(7,5): message : or       'A::A(void)'
1>e:\temp\ConsoleApplicationMangled\ConsoleApplicationMangled\ConsoleApplicationMangled.cpp(18,2): message : while trying to match the argument list '()'
1>e:\temp\ConsoleApplicationMangled\ConsoleApplicationMangled\ConsoleApplicationMangled.cpp(18,2): message : This diagnostic occurred in the compiler generated function 'void A::__dflt_ctor_closure(void)'
1>Done building project "ConsoleApplicationMangled.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Upvotes: 1

Adrian Mole
Adrian Mole

Reputation: 51845

The only way that I can see (if you really need both constructors) is to remove the default value of the argument in the second constructor and make the 'default' constructor call that:

class A {
public:
    A() : A(5) {
        std::cout << "ctor\n";
    }

    A(int i) {
        std::cout << "ctor -> v\n";
    }

    virtual ~A() {
        std::cout << "dtor\n";
    }
};

But then, for the default ('empty') instatiation, the body code for both constructors will execute.

Upvotes: 1

Related Questions