нет перегрузки 'max' соответствия 'std :: function ' - PullRequest
1 голос
/ 20 февраля 2020

Этот код не компилируется и выдает ошибку:

test.cpp:12:4: error: no matching function for call to 'func'
   func(std::max<int>);
   ^~~~
test.cpp:4:6: note: candidate function not viable: no overload of 'max' matching 'std::function<const int &(const int &, const int &)>' for 1st argument
void func(std::function<const int &(const int &, const int &)> a)
     ^
1 error generated.
#include<iostream>
#include<functional>
#include <algorithm>

void func(std::function<const int &(const int &, const int &)> a)
// void func(const int &a(const int &, const int &))       //this one works
{
   std::cout << a(4,5) << std::endl;
}

int main(int argc, char const *argv[])
{
   func(std::max<int>);
}

Ранее я использовал указатель на функцию с той же сигнатурой аргумента, что и std::function, и это сработало. Что тут происходит?

1 Ответ

5 голосов
/ 20 февраля 2020

Функция std не является указателем функции.

Имя функции шаблона испытывает разрешение перегрузки при вызове или при приведении к указателю на функцию. Он не имеет разрешения перегрузки при передаче в стандартную функцию.

std::max<int> может относиться к более чем одной функции; те, которые принимают список инициализаторов или два аргумента int с, и каждый из них имеет перегрузки, которые принимают компараторы или нет.

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

int x00 = std::max<int>( std::initializer_list<int>{1,2,3,4} )
int x01 = std::max<int>( 2, 4 );
int x10 = std::max<int>( std::initializer_list<int>{1,2,3,4}, [](int a, int b){ return b>a; } )
int x11 = std::max<int>( 2, 4, [](int a, int b){ return b>a; } );

, сказав, std::max<int> вы говорите, что используется один из этих 4-х.

И да, только один из них работает с std::function, но код языка C ++, который вызывает std::function, не знает этого, поэтому говорит, что результат неоднозначен. (обратите внимание, что два из перечисленного являются бесконечным набором возможных сигнатур).

Между тем,

int const&(*ptr)(int const&,int const&) = std::max<int>;

здесь, мы делаем разрешение перегрузки. Мы выбираем std::max<int>, который занимает два int с.

std::function<int const&(int const&, int const&)> f = std::max<int>;

, здесь мы не делаем разрешение перегрузки для std::max.

. Это легко исправить:

std::function<int const&(int const&, int const&)> f =
  [](auto&&...args)->decltype(auto)
  { return std::max<int>(decltype(args)(args)...); };

, который я иногда пишу как макрос

#define RETURNS(...) \
  noexcept(noexcept( __VA_ARGS__ )) \
  -> decltype( __VA_ARGS__ ) \
  { return __VA_ARGS__; }
#define CALL(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__( decltype(args)(args)... ) )

, давая нам:

std::function<int const&(int const&, int const&)> f = CALL(std::max<int>);

здесь I задержка разрешение перегрузки до тех пор, пока мы вызвать вызываемый объект, который мы передаем f. На данный момент типы известны, поэтому все работает.

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