我遇到了以下代码的问题:
#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>>'
我想知道引擎盖下的内容以及为什么它不起作用。 受保护的成员是在谈论什么?
答案 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));
// ^^^^^^^^^^^^^^^^^^^
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)));
^^^^^^^^