标准库方法的成员函数指针问题

Member function pointer issue with standard library methods

这个问题来自
Passing a member function pointer to an overloaded class method into a template function.
你不需要阅读它来理解这个问题。可能这两个问题都会有相同的答案。

我得到 compiler error for below simple code.

#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
  T obj;  // Found and declared an object of actual container class
  (obj.*Method)(1);  // Some processing
  return obj;  // Returned that container class object with RVO
} 
int main ()
{
  ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}

错误很有趣:

 In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
   ReceiveFuncPtr(&std::set<int>::insert); // ERROR
                                        ^   
note: candidate is: 
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
 T ReceiveFuncPtr (Return (T::*Method)(const int&))
   ^   
note:   template argument deduction/substitution failed:
note:   mismatched types 'const int&' and 'std::initializer_list<int>'
   ReceiveFuncPtr(&std::set<int>::insert); // ERROR
                                        ^   
note:   mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note:   mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note:   mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note:   couldn't deduce template parameter 'Return'

如果您仔细查看 注释,那么编译器似乎与除正确方法之外的所有其他方法匹配!在这种情况下,编译器应该匹配 insert(const std::set<int>::value_type&) 又名 const int&。如果我更改 ReceiveFuncPtr() 以匹配其他一些重载,它将再次通过跳过该重载而失败。

为了调试这种情况,我创建了 std::set 的手工版本。但是 compiles fine:

template<typename T, typename T2 = void>
struct MySet
{
  std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
  std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
  void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
  ReceiveFuncPtr(&MySet<int>::insert);  // OK
}

网上冲浪后,我遇到了这个post:
What are the rules for function pointers and member function pointers to Standard functions?

虽然有关联,但没有解决问题。

问题:为什么在标准库方法的情况下成员函数替换失败,而手写class方法传递同样的东西?

更新:

看了正确答案后,确定insert不能用。唯一的方法是丑陋的类型转换,这对这个问题来说是一种矫枉过正。
一种优雅的 解决方案 是使用 std::set<int>::emplace<const int&>,它只有 templated 版本,不像 insert 混合了 template 和非 template版本。
调用函数如下:

ReceiveFuncPtr(&std::set<int>::emplace<const int&>);

以上 compiles fine.

问题不在于您在 MySet 中显示的 insert 函数。问题出在您省略的其中一个。具体来说:

template< class InputIt >
void insert( InputIt first, InputIt last );

来自[temp.deduct.call]:

When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.

由于&std::set<int>::insert正是这样一个重载集,参数是非推导上下文,无法解析。您的 MySet 示例不包含 insert 的函数模板重载,这就是它工作正常的原因。如果你加一个,你会发现它也会编译失败。