Перегрузка шаблона C ++ - вызвана неправильная функция - PullRequest
2 голосов
/ 06 июня 2010
        template<typename T> T* Push(T* ptr);
        template<typename T> T* Push(T& ref);
        template<typename T, typename T1> T* Push(T1&& ref);

У меня есть

        int i = 0;
        Push<int>(i);

Но компилятор называет это неоднозначно. Как это двусмысленно? Вторая функция явно предпочтительнее, так как она более специализированная. Тем более, что T1 && не будет привязываться к lvalue, если я не переместлю его явно / вперед.

Извините, я - инт. В противном случае вопрос не имел бы смысла, и я думал, что люди сделают это, поскольку обычно это итератор цикла.

1 Ответ

7 голосов
/ 06 июня 2010

Если i является целым числом, то первое не является жизнеспособным. Последние два остаются. Затем для вычета i, второй и третий оба дают одинаковые типы функций для разрешения перегрузки (оба int& в качестве параметра). Таким образом, вы должны полагаться на частичный заказ.

Однако частичное упорядочение не может отличить их друг от друга. Для контекста частичного упорядочения вызова функции только параметры используются для определения порядка (и тип возвращаемого значения в вашем примере не рассматривается), и любой модификатор ссылки отделен от них. Таким образом, вам удастся определить тип параметра от одного к другому в обоих направлениях - оба типа параметров будут по меньшей мере столь же специализированными, как и другие параметры соответственно. И ни один из них не применяется, поэтому ни один не является более специализированным, чем другой.

Существует заполнитель отчета о проблеме, целью которого является выяснение всего, что связано с трудностями ссылки на rvalue / lvalue во время частичного заказа. Подробнее см. в этом вопросе usenet .

Если какой-либо из этих двух пунктов будет более специализированным, я бы сказал, что он должен быть первым. В конце концов, он принимает меньше аргументов, чем другой (другой является потенциальным совершенным перенаправителем).


Тем более, что T1 && не будет привязываться к lvalue, если я явно не переместлю / переместлю его.

На самом деле, он примет все. Наличие параметра типа T&& в шаблоне переключит на «perfect-forwarding-deduction-mode», который выведет T к типу аргумента, если это значение rvalue, и добавит модификатор lvalue-reference к тип T, если это lvalue. Таким образом, если аргумент является lvalue, результирующий тип параметра будет T& && свернут до T&, что прекрасно принимает lvalue (как в вашем случае).

С другой стороны, вы пытаетесь перегрузить функцию захвата объектов, перемещая их. Но это не сработает из-за специального вычета, сделанного для T&& (см. Ниже). Просто удалите первую функцию и напишите свой код как

template<typename T, typename T1> T* Push(T1&& ref) {
  /* for lvalues, T1 is U& and rvalues it is U, with U being the
   * argument type. */
  T t1(std::forward<T1>(ref));

  /* whatever needs to be done ... */
}

Это будет перемещать-конструировать t1, если аргумент был значением rvalue, и копировать ref, если аргумент был значением lvalue или если T не имеет конструктора перемещения. Это просто иллюстрация, это может быть не то, что вам действительно нужно делать, в зависимости от вашего реального варианта использования. Я также не уверен, почему у вас есть два типа параметров шаблона здесь. Я предлагаю избавиться от T и вместо этого сказать typename remove_reference<T1>::type * для возвращаемого типа. Так что вы можете извлечь выгоду из аргумента вычета.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...