Search code examples
c++c++11standardsvariable-declarationfunction-declaration

How to solve ambiguous declarations elegantly in C++11?


struct A
{
    A(int) {}
    A(std::initializer_list<int>) {}
};

template<typename T>
struct B
{
    B(A) {}
    B(std::initializer_list<T>) {}
};

int main()
{
    int n{};
    B   m1(A{n}); // error: call A::A(std::initializer_list<int>)
    B   m2(A(n)); // error: just a function declaration: B m2(A n);
}

As shown in the code above, I want to call B::B(A(int)) to construct an object of class B. I have two choices:

  1. B m1(A{n});
  2. B m2(A(n));

According to C++ Core Guidelines, the former is preferred.

However, B m1(A{n}); will call A::A(std::initializer_list<int>) rather than A::A(int), which is not intended. So, I have to use B m2(A(n));, but it is just a function declaration: B m2(A n);!

How to solve ambiguous declarations elegantly in C++11?


Solution

  • The almost always auto idiom to the rescue.

    I'm not sure what you intended T to be, since it is unclear in the code example. I used double because... why not.

    int main() {
        auto n = int{};
        auto m1 = B<double>(A{n});
        auto m2 = B<double>(A(n));
    }
    

    Disclaimer: about half the C++ developers I talk to in real life (at my job) absolutely despise almost always auto. I like it (but I've done a lot of C# with var, F#, and TypeScript, where that's business as usual; and C++ template code and lambda-with-auto), but there are many who are ardently anti auto. If you decide to use almost always auto in your own project, I strongly urge you to discuss with your co-workers and get team consensus before going down that path.