为什么不能将mem_fn应用于std :: string的成员函数?

时间:2015-06-11 01:27:55

标签: c++

struct int_holder {
    int value;
    int triple() {return value*3;}
};

int main(int argc, const char * argv[])
{
    std::string abc{"abc"};
    int_holder one{1};

    auto f1 = mem_fn(&std::string::clear);
    auto f2 = mem_fn(&int_holder::triple);
    f1(abc);
    f2(one);
}

我在Xcode中测试这样的代码,编译器发出这样的错误 enter image description here

似乎mem_fn对于用户定义的类的成员函数没有问题,但是没有标准字符串的成员函数,它们有什么不同,为什么? 感谢您的阅读,帮助我PLZ!

2 个答案:

答案 0 :(得分:2)

我可以使用Clang 3.1-3.3 as well as 3.6重现这一点。看起来像bug 16478

最简单的解决方法是使用lambda或等效的。其他完全不可移植的解决方法包括使用

禁用extern模板
#ifndef _LIBCPP_EXTERN_TEMPLATE
#define _LIBCPP_EXTERN_TEMPLATE(...)
#endif
在包含任何标题之前

(实质上是应用r189610);并对成员函数(template void std::string::clear();)或整个类进行显式实例化。

那就是说,你不应该使用标准库类的成员函数的地址。 [member.functions] / P2:

  

实现可以声明其他非虚拟成员函数   班级中的签名:

     
      
  • 通过向成员函数签名添加具有默认值的参数; 187
  •   
  • 通过两个或多个具有等效行为的成员函数签名替换具有默认值的成员函数签名;和
  •   
  • 通过为成员函数名称添加成员函数签名。
  •   
     

187)因此,一个类的成员函数的地址   C ++标准库具有未指定的类型。

答案 1 :(得分:0)

对于标准,你不能指向任何标准的非静态成员,因为允许库实现添加隐藏的重载,默认的函数模板参数,返回类型的SFINAE等。

换句话说,& std::string::clear根本不是受支持的操作。

就Clang而言,它看起来像隐藏符号可见性的问题。每个共享对象(链接器输出)文件都有自己的某些函数副本,以避免第三方共享库实现标准库的外观。随着不同的副本浮动,PTMF上的相等运算符将无法工作:如果从内联函数保留值& std::string::clear,则以后可能无法比较等于它自身。但是,它可能是一个错误,因为std::string应该由libc++.so共享库完全实现。只有std::basic_string的其他专业才能证明这种行为是合理的。

一个好的解决方法是使用lambda代替。 []( std::string & o ) { o.clear(); }mem_fn的替代品。它避免了间接调用,其sizeof更小。实际上,除非绝对必要,否则不应使用mem_fn