Ошибка в концепциях C++20 с функциями-членами шаблона и std::invocable
Я экспериментировал с концепциями C ++ 20 и библиотекой Eigen и обнаружил неожиданное поведение. В частности, рассмотрите следующую концепцию, требующую, чтобы тип мог быть вызван с помощью
Eigen::Matrix<double, -1, 1>>
объект или
Eigen::Matrix<char, -1, 1>>
один:
template <class FOO_CONCEPT>
concept FooConcept = std::invocable<FOO_CONCEPT, Eigen::Matrix<double, -1, 1>> &&
std::invocable<FOO_CONCEPT, Eigen::Matrix<char, -1, 1>>;
Затем посмотрите на закомментированную строку (*) в следующей структуре:
struct Foo {
// template <typename T> <---- (*)
void operator()(Eigen::Matrix<double, -1, 1>) {
}
void operator()(Eigen::Matrix<float, -1, 1>) {
}
};
Обратите внимание, что класс
Foo
не удовлетворяет требованиям
FooConcept
поскольку его нельзя вызвать с аргументом. Действительно:
std::cout << FooConcept<Foo> << std::endl;
отпечатки
0
. Однако, когда я переключаю строчный комментарий (*), т. Е. Когда
operator()
это шаблон, как ни странно печатается тот же код. Это ошибка? Я получил эти результаты, используя Clang 12.0.1 и GCC 11.1.0 для компиляции кода в Visual Studio Code. Спасибо за любую помощь, которую вы можете оказать!
PS: линия
std::cout << std::is_convertible<Eigen::Matrix<char, -1, 1>, Eigen::Matrix<float, -1, 1>>()
<< std::endl;
отпечатки
1
, но
Eigen::Matrix<char, -1, 1>
объект не может быть неявно преобразован в
Eigen::Matrix<float, -1, 1>
. Это очередная ошибка? И связано ли это как-то с вышеупомянутой проблемой?
1 ответ
Конвертируемый просто определяет, существует ли перегрузка. В случае Эйгена преобразование перегрузки между этими типами существует, но тело имеет
static_assert
.
is_convertable
никак не инстанцирует тело конверсионной операции , прежде чем сказать это работает. Это сделано намеренно, чтобы разрешение перегрузки C ++ не требовало компиляции огромного количества кода.
Чтобы ваши черты работали, Eigen необходимо переписать, чтобы он поддерживал методы и операторы преобразования, удобные для "SFINAE".
Сбой в вашем тесте был вызван тем, что матрица символов преобразована в оба, что неоднозначно, поэтому признак не работает. Вы не поэтому думали, что это не удалось.
Добавление
template<class T>
означает, что перегрузка thst не учитывается (невозможно вывести значение T), поэтому однозначно выбрано преобразование в массив с плавающей запятой.