标准库方法

时间:2015-07-09 11:33:00

标签: c++ templates c++11 standard-library member-function-pointers

这个问题来自于 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'

如果仔细查看 note ,那么看起来编译器匹配除了正确的其他方法之外的所有其他方法!在这种情况下,编译器应该匹配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
}

冲浪之后,我发现了这个帖子:
What are the rules for function pointers and member function pointers to Standard functions?

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

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

更新

在查看正确答案后,我确信insert无法使用。唯一的办法就是丑陋的类型转换,这对这个问题来说太过分了 一个优雅的解决方案是使用仅std::set<int>::emplace<const int&> d版本的template,而不像template和非template版本混合的插件。<登记/> 调用该函数如下:

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

高于compiles fine

1 个答案:

答案 0 :(得分:7)

问题不在于insert中显示的MySet功能。问题在于你省略了哪一个。具体做法是:

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

来自[temp.deduct.call]:

  

当P是函数类型时,指向函数类型的指针或指向成员函数类型的指针:
   - 如果参数是包含一个或多个函数模板的重载集,则会处理该参数   作为一个非演绎的背景。

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