Выведены конфликтующие типы для универсальной ссылки и указателя на элемент

Я хочу такую ​​функцию:

template<typename C, typename T>
void foo(C &&aclass, T (C::*const memberFunc)(unsigned)) {

}

Параметры (словами, потому что синтаксис типа C/C++ является ментальным):

  • Универсальная ссылка на класс, например. MyClass.
  • Константный указатель на функцию-член MyClass, которая принимает целое число без знака и возвращает T.

Этот вид работает, однако, если я вызываю его со ссылкой на l-значение в качестве первого параметра, я получаю сообщение об ошибке, например:

шаблон-кандидат игнорируется: выведены конфликтующие типы для параметра «C» («MyClass &» против «MyClass»)

Насколько я понимаю, он выводит C из первого и второго параметров, но выводит разные выводы и путается.

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

Этот ответ также полезен, но они решают его, просто не используя ссылки для C вообще, что в этом случае одинаково эффективен, но не в моем случае.

Это возможно?


person Timmmm    schedule 21.02.2018    source источник
comment
Осмелюсь сказать, что возлагать на C ответственность за синтаксис, которого у него нет, несправедливо.   -  person StoryTeller - Unslander Monica    schedule 21.02.2018
comment
Я имел в виду, что синтаксис, используемый для указания типов в C, сумасшедший. В C++ результат зачастую хуже, потому что его типы более сложны, но сложный синтаксис исходит из С.   -  person Timmmm    schedule 21.02.2018


Ответы (2)


С lvalues ​​C будет выводиться как тип lvalue-reference (т.е. MyClass & для вашего случая) для 1-го параметра, что является ожидаемым поведением ссылка на пересылку; вы можете удалить ссылку через std::remove_reference при использовании C в второй параметр, например.

template<typename C, typename T>
void foo(C &&aclass, T (std::remove_reference_t<C>::*const memberFunc)(unsigned)) {

}

И, как указал @Quentin, использование std::remove_reference также вводит недедуцируемый контекст, это предотвратило бы вывод C из 2-го параметра.

person songyuanyao    schedule 21.02.2018
comment
Стоит отметить, что std::remove_reference также вводит невыведенный контекст, что очень полезно. - person Quentin; 21.02.2018
comment
Вы имели в виду _t в конце remove_reference? - person Timmmm; 21.02.2018
comment
@Тимммм Да. Эта функция появилась в C++14; в С++ 11 вы можете вместо этого написать typename std::remove_reference<C>::type. - person songyuanyao; 21.02.2018

На самом деле я только что обнаружил, что универсальная эталонная перегрузка перенаправляет ее на эталонную версию с l-значением. Однако не особенно элегантно; Я чувствую, что должен быть лучший способ.

template<typename C, typename T>
void foo(C &aclass, T (C::*const memberFunc)(unsigned)) {
  // Code goes here.
}

template<typename C, typename T>
void foo(C &&aclass, T (C::*const memberFunc)(unsigned)) {
  foo(aclass, memberFunc);
}
person Timmmm    schedule 21.02.2018