slashmais
slashmais

Reputation: 7155

Ambiguity not picked up by compiler

I had to spent some time in finding and fixing a bug that I managed to isolate in the following code:

#include <iostream>

struct A
{
    std::string S;
    A(const std::string s) { S = s; }
};

void f1(A a) { std::cout << "f1:a.S = " << a.S << "\n"; }
void f1(const std::string s) { std::cout << "f1:s = " << s << "\n"; }

void f2(A a) { std::cout << "f2:a.S = " << a.S << "\n"; }

int main()
{
    f1(A("test"));
    f1(std::string("test"));

    f2(A("test"));
    f2(std::string("test"));

    return 0;
}

The bug was caused by the overlooked (by me and the compiler(?)) ambiguity created by the f1-function: f2 clearly shows that both f1(A) and f1(std::string) apply to A, but when compiled the ambiguity is not picked-up by the compiler, and when executed the output is:

f1:a.S = test
f1:s = test
f2:a.S = test
f2:a.S = test

Is this behavior correct? Compiler problem? Or just plain old PIBCAK?

Upvotes: 3

Views: 348

Answers (1)

James McNellis
James McNellis

Reputation: 355009

The behavior that you describe is expected: there is no ambiguity. An overload resolution ambiguity occurs when two overloads match equally well and are both "the best overload."

When you call f1 with an argument of type A, the first f1 is an exact match; the second f1 does not match at all. Thus, f1 obviously wins during overload resolution.

When you call f1 with an argument of type std::string, the first f1 matches via the converting constructor of A; the second f1 is an exact match. The second f1 is a better match: it's an exact match and no conversion is required. The two overloads do not match equally well, thus there is no ambiguity. The second f1 wins during overload resolution.

Upvotes: 8

Related Questions