Проблемы с порядком разрешения конструктора - PullRequest
7 голосов
/ 18 августа 2011

Рассмотрим следующие конструкторы для T:

struct T {
    T(const bool) { std::cout << "T(const bool)" << endl; }
    T(const std::string&) { std::cout << "T(const std::string&)" << endl; }
};

T t("");
  1. Почему T(const bool) имеет приоритет над T(const std::string&) при построении t?
  2. Поскольку вышеприведенный приоритет может вызвать путаницу у пользователей, ожидающих вызова T(const std::string&), что я могу сделать, чтобы T(const std::string&) вызывался неявно при передаче строковых литералов в конструктор T. На данный момент единственная работа Я нашел, чтобы добавить еще один конструктор, который имеет самый высокий приоритет:

    T(const char* s)
    {
        std::cout << "T(const char*)" << endl;
        *this = std::string(s);
    }
    
  3. Помимо вышеприведенного решения, объявление explicit T(const bool) во избежание путаницы не решает вышеуказанную проблему: в этом случае, хотя T t = "" сейчас запрещен, почему форма T t("") все еще разрешена и делает Звоните T(const bool)?

Ответы [ 3 ]

8 голосов
/ 18 августа 2011

Почему T(const bool) имеет приоритет над T(const std::string&) при построении t?

"" типа char[1];это неявно преобразуется в char const* через преобразование массива в указатель.Указатель неявно преобразуется в bool, причем все ненулевые указатели становятся true, а все нулевые указатели становятся false.Оба являются «встроенными» стандартными преобразованиями.

Преобразование char const* -> std::string является объявленным пользователем преобразованием: оно использует конструктор преобразования std::string, который принимает char const*.

Стандартные («встроенные») преобразования предпочтительнее, чем объявленные пользователем преобразования при разрешении перегрузки, поэтому конструктор, принимающий bool, здесь лучше, чем конструктор, принимающий std::string.

Пока единственное, что я нашел, - это добавление еще одного конструктора

Это звучит как разумное решение;безусловно, самое простое решение для простого сценария, который вы описываете.Хотя вы используете присвоение *this немного неуклюже;было бы лучше, чтобы оба конструктора делегировали какую-то функцию инициализации.

В качестве альтернативы вы можете использовать шаблон с enable_if для любых конструкторов, для которых вы хотите запретить преобразования:

template <typename U>
T(U, std::enable_if<std::is_same<U, bool>::value>::type* = 0) { }

Этот конструктор будет вызываться только с аргументом bool и ничем иным.Вы можете найти enable_if и is_same в Boost, C ++ TR1 или C ++ 0x.Вы также можете использовать !is_pointer, is_integral или какую-либо другую комбинацию признаков типа, чтобы учесть некоторые другие типы аргументов, но не char const*.

Или, в качестве другой альтернативы, вы можете отказаться от boolв целом и используйте свое собственное перечисление с перечислителями, соответствующими true и false для конструктора.То, имеет ли это смысл, зависит от вашего варианта использования.

Объявление explicit T(const bool) во избежание не решает вышеуказанную проблему ... почему форма T t("") все еще разрешена и вызывает T(const bool)?

explicit запрещает только неявные преобразования в T.T t(""); вообще не имеет преобразований в T;он напрямую инициализирует объект t, создавая его с аргументом "", передаваемым какому-либо конструктору, наиболее подходящему.

1 голос
/ 18 августа 2011

"" можно конвертировать как в std::string, так и в bool.

Вопрос в том, как он будет конвертироваться?

  • Преобразование в std::string является определяемым пользователем преобразованием.
  • Преобразование в bool является стандартным преобразованием.

Таким образом, ответстандартное преобразование имеет более высокий приоритет по сравнению с пользовательским преобразованием.Таким образом, "" преобразуется в bool.

Пример,

struct A
{
   A(int i) {} //i.e an int can implicity convert to A
};

void f(const A &) { cout << "User-defined conversion won" << endl; }
void f(const bool &) { cout << "Standard conversion won" << endl; }

int main() {
        f (10);
        return 0;
}

Вывод:

Standard conversion won

Демонстрационная версия онлайн: http://www.ideone.com/5Bt0K

В приведенной выше демонстрации 10 может конвертировать в A и bool оба.Поскольку преобразование в bool является стандартным преобразованием, оно конвертируется в bool вместо A.

0 голосов
/ 18 августа 2011

Поскольку преобразование, определенное пользователем, не учитывается при наличии встроенного.

Используйте третий конструктор, который принимает const char*.Нет лучшего способа.

...