For_each和指向成员函数的指针

时间:2015-05-31 17:15:15

标签: c++ stl

我遇到了以下代码的问题:

#include <list>
#include <algorithm>
#include <string>
#include <iostream>
#include <functional>
using namespace std;

struct Person {
    string name;
    ostream& print(ostream& out) const {
        return out << name;
    }
};

int main()
{
    Person p = { "Mark" };
    list<Person> l;
    l.push_back(p);
    for_each(l.begin(), l.end(), bind(&Person::print, std::placeholders::_1, std::cout)); // this placeholder is not a pointer so it can't work anyways

    // I also tried something with lambdas like this but it doesn't work either
    //for_each(l.begin(), l.end(), bind([](Person& p, ostream& out) { mem_fun(&Person::print)(&p, out); }, std::placeholders::_1, cout));

    // it doesn't even work that way
    //for_each(l.begin(), l.end(), bind([](Person& p, ostream& out) { p.print(out); }, std::placeholders::_1, cout));
}

这是一条错误消息(在每种情况下)

microsoft visual studio 12.0\vc\include\tuple(80): error C2248: 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream' : cannot access protected member declared in class 'std::basic_ostream<char,std::char_traits<char>>'

我想知道引擎盖下的内容以及为什么它不起作用。 受保护的成员是在谈论什么?

3 个答案:

答案 0 :(得分:3)

您的for_each电话(以及关联的bind)正在尝试复制std::cout(无论print本身是否参考),这是不可能的,因为流是非能够复制。

在C ++ 03中,强制执行不可复制性的唯一方法是将其复制构造函数声明为protected(或private),因此您会看到错误。< / p>

改为通过std::ref (std::cout)

答案 1 :(得分:3)

如果您希望std::cout通过引用传递print(),则需要使用std::ref。否则,将尝试使用它的副本,因为std::for_each按值获取其仿函数参数,并且std::cout的类型不可复制: 1

for_each(l.begin(), 
         l.end(), 
         bind(&Person::print, std::placeholders::_1,  std::ref(std::cout));
//                                                    ^^^^^^^^^^^^^^^^^^^

Live example

1 您所看到的关于protected复制构造函数无法访问的消息是由于您正在使用的标准库的实现,非通过使类的副本构造函数非public来实现可复制性。这是在C ++ 03中实现不可复制性的唯一方法 - 从C ++ 11开始,惯用的方法是将复制构造函数定义为已删除

答案 2 :(得分:3)

问题是std::bind表达式将导致其参数的副本。 std::cout不是来自可复制类型,因此错误。您可以通过传递std::reference_wrapper来解决此问题。您可以使用std::ref

制作其中一个
for_each(l.begin(), l.end(), 
         bind(&Person::print, std::placeholders::_1, std::ref(std::cout)));
                                                     ^^^^^^^^