Enums, Constructor overloads с аналогичными преобразованиями - PullRequest
3 голосов
/ 28 мая 2010

Почему VisualC ++ (2008) запутывается: «C2666: 2 перегрузки имеют похожие преобразования», когда я указываю enum в качестве второго параметра, но не когда я определяю тип bool?

Не должно ли совпадение типов уже исключать второй конструктор, потому что он имеет тип 'basic_string'?

#include <string>
using namespace std;

enum EMyEnum { mbOne, mbTwo };
class test {
public: 
#if 1 // 0 = COMPILE_OK, 1 = COMPILE_FAIL
    test(basic_string<char> myString, EMyEnum myBool2) { }
    test(bool myBool, bool myBool2) { }
#else
    test(basic_string<char> myString, bool myBool2) { }
    test(bool myBool, bool myBool2) { }
#endif
};

void testme() {
    test("test", mbOne);
}

Я могу обойти это, указав ссылку 'т.е. basic_string & myString ', но не в случае, если это const basic_string & myString'.

Также вызывается явно через "test ((basic_string)" test ", mbOne);" тоже работает.

Я подозреваю, что это как-то связано с каждым выражением / типом, разрешаемым в bool через "! = 0".

Любопытно, что комментарии все же:)

1 Ответ

5 голосов
/ 28 мая 2010

Причина неоднозначности заключается в том, что одна функция-кандидат лучше, чем другая функция-кандидат, только если ни один из ее параметров не хуже, чем параметры другой.

Проблема в том, что строковый литерал, имеющий тип const char[5], может быть преобразован как в std::string (через конструктор преобразования), так и в bool (поскольку массив может распадаться на указатель и любой указатель неявно преобразуется в bool). Преобразование в bool является предпочтительным, потому что это стандартное преобразование, а стандартные преобразования предпочтительнее пользовательских преобразований.

Итак, рассмотрим «сломанные» перегрузки:

test(basic_string<char> myString, EMyEnum myBool2) { }  // (1)
test(bool myBool, bool myBool2) { }                     // (2)

Первый аргумент является const char[5] и предпочитает (2) (согласно описанию выше). Второй аргумент - EMyEnum и предпочитает (1), что является точным соответствием; требуется преобразование, чтобы соответствовать (2) (перечисление может быть неявно преобразовано в bool).

Теперь рассмотрим второй случай:

test(basic_string<char> myString, bool myBool2) { }    // (3)
test(bool myBool, bool myBool2) { }                    // (4)

Первый аргумент по-прежнему предпочитает (4), но теперь второй аргумент может одинаково соответствовать (3) и (4). Таким образом, компилятор может выбрать (4), и двусмысленности нет.

Не было бы никакой двусмысленности, если бы вы исключили требуемое преобразование для первого аргумента, например,

test(basic_string<char>("test"), mbOne);

потому что оба аргумента будут точно соответствовать (1).

...