Перегрузка шаблона C++ - вызвана неправильная функция

        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 ответ

Решение

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

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

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

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


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

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

С другой стороны, вы, похоже, пытаетесь сделать это, перегружая функцию захвата объектов, перемещая их. Но это не сработает из-за специального вычета, сделанного для 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 если аргумент был значением r, и скопируйте ref если аргумент был lvalue или если T не имеет конструктора перемещения. Это просто иллюстрация, это может быть не то, что вам действительно нужно делать, в зависимости от вашего реального варианта использования. Я также не уверен, почему у вас есть два типа параметров шаблона здесь. Я предлагаю избавиться от T, и скажи typename remove_reference<T1>::type * вместо возвращаемого типа. Так что вы можете получить от вывода аргумент.

Другие вопросы по тегам