'max' 没有重载匹配 'std::function<const int &(const int &, const int &)>'

Iam*_*non 1 c++ function

此代码无法编译,并给出错误:

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.
Run Code Online (Sandbox Code Playgroud)
#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>);
}
Run Code Online (Sandbox Code Playgroud)

我以前使用了一个具有相同参数签名的函数指针,std::function并且可以正常工作。这里发生了什么?

Yak*_*ont 5

std 函数不是函数指针。

模板函数的名称在调用或转换为函数指针时会遇到重载解析。传递给 std 函数时,它不会遇到重载解析。

std::max<int>可以引用多个函数;采用一个初始化列表或两个ints参数的参数,并且每个参数都有带比较器或不带比较器的重载。

对于重载决议,除了其中之一之外的所有内容都被丢弃。没有,结果是模棱两可的。

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; } );
Run Code Online (Sandbox Code Playgroud)

std::max<int>你是说正在使用这 4 个中的一个。

是的,只有其中一个可以使用std::function,但是调用 的 C++ 语言代码std::function不知道这一点,所以它说结果不明确。(请注意,以上两个是无限的可能签名集)。

同时,

int const&(*ptr)(int const&,int const&) = std::max<int>;
Run Code Online (Sandbox Code Playgroud)

在这里,我们正在做重载解析。我们选择std::max<int>需要两个ints 的。

std::function<int const&(int const&, int const&)> f = std::max<int>;
Run Code Online (Sandbox Code Playgroud)

这里我们不对 进行重载解析std::max

一个简单的解决方法是:

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

我有时写成一个宏

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

给我们:

std::function<int const&(int const&, int const&)> f = CALL(std::max<int>);
Run Code Online (Sandbox Code Playgroud)

在这里,我重载决议延迟到我们调用我们传递的可调用对象之后f。那时类型是已知的,所以一切正常。