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

iam*_*ind 6 c++ templates member-function-pointers standard-library c++11


将成员函数指针传递给模板函数的重载类方法产生了这个问题.
你不需要阅读它来理解这个问题.可能两个问题都有相同的答案.

以下简单代码我收到编译器错误.

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

错误很有趣:

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

如果仔细观察音符,那么看起来编译器匹配除了正确的方法之外的所有其他方法!在这种情况下,编译器应该匹配insert(const std::set<int>::value_type&)aka const int&.如果我改变ReceiveFuncPtr()匹配其他一些重载,它将通过跳过该重载再次失败.

为了调试这种情况,我创建了手工版本std::set.但编译很好:

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

冲浪之后,我遇到了这个帖子:
标准函数的函数指针和成员函数指针的规则是什么?

虽然它是相关的,但它并没有解决问题.

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

更新:

看了正确答案后,我确信insert无法使用.唯一的方法是丑陋的类型转换,这对这个问题来说太过分了.
一个优雅的解决方案是使用std::set<int>::emplace<const int&>只有templated版本的插件,它具有混合template和非template版本.
调用如下函数:

ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Run Code Online (Sandbox Code Playgroud)

以上编译很好.

Bar*_*rry 7

问题不在于insert您展示的功能MySet.问题在于你省略了哪一个.特别:

template< class InputIt >
void insert( InputIt first, InputIt last );
Run Code Online (Sandbox Code Playgroud)

来自[temp.deduct.call]:

当P是函数类型时,指向函数类型的指针或指向成员函数类型的指针:
- 如果参数是包含一个或多个函数模板的重载集,则该参数将被视为非推导上下文.

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