我正在尝试使用C++11特性来使定制的流操作器更容易创建。我可以使用lambda函数作为操作器,但不能使用std::function<ostream&(ostream&)>。
这是代码,简化如下:
#include <iostream>
#include <functional>
using namespace std;
auto lambdaManip = [] (ostream& stream) -> ostream& {
stream << "Hello world" << endl;
};
function<ostream& (ostream&)> functionManip = [] (ostream& stream) -> ostream& {
stream << "Hello world" << endl;
};
int main (int argc, char** argv) {
cout << lambdaManip; // OK
cout << functionManip; // Compiler error
}第二个cout语句失败如下:
g++-4 src/Solve.cpp -c -g -std=c++0x -o src/Solve.o -I/home/ekrohne/minisat
src/Solve.cpp: In function 'int main(int, char**)':
src/Solve.cpp:24:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/include/c++/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = std::function<std::basic_ostream<char>&(std::basic_ostream<char>&)>]'为什么会失败呢?我用的是西格温gcc 4.5.3。
尽管我在问这个问题,但由于效率问题,我并不热衷于在任何地方使用std::function。但是,我确实希望编写返回lambda函数的函数,并且不知道如何在没有std::function的情况下这样做。例如,下面这样的内容会很好
auto getAdditionFunctor();
auto getAdditionFunctor() {
return [] (int x, int y) { return x + y };
};...but显然不起作用。是否有其他的语法起作用?我无法想象它会是什么样子,所以我可能被std::function困住了。
如果我能解决第二个问题,那么第一个问题就没有意义了。
谢谢。
定义operator<<(ostream&, std::function<ostream&(ostream&)>是有帮助的。我误读了一个网页,给人的印象是ostream足够聪明,可以把一个有operator()的任意物体当作操纵者。我搞错了。此外,我构建的简单lambda可能只是被编译成一个简单的旧函数,就像我被告知的那样。实际上,如果我使用变量捕获来确保lambda不是一个简单的函数,那么编译器就会失败。此外,定义了operator()的对象(默认情况下)不被视为操纵器:
class Manipulator {
ostream& operator()(ostream& stream) const {
return stream << "Hello world" << endl;
};
} classManip;
function<ostream& (ostream&)> functionManip = [] (ostream& stream) -> ostream& {
return stream << "Hello world" << endl;
};
int main (int argc, char** argv) {
const string str = "Hello world";
auto lambdaManip = [&] (ostream& stream) -> ostream& {
return stream << str << endl;
};
cout << classManip; // Compiler error
cout << lambdaManip; // Compiler error
cout << functionManip; // Compiler error
}进一步更新:这是一个比下面的解决方案更健壮的解决方案,可以通过以下方法实现:
// Tell ostreams to interpret std::function as a
// manipulator, wherever it sees one.
inline ostream& operator<<(
ostream& stream,
const function<ostream& (ostream&)>& manipulator) {
return manipulator( stream );
}这段代码有一个额外的const。我发现这是为了在我的项目中实际实现解决方案。
发布于 2012-10-22 00:59:09
如果您查看operator<< for ostream,获取std::function没有过载现象--这基本上就是您在使用cout << functionManip时要做的事情。要解决这个问题,可以自己定义重载:
ostream& operator<<(ostream& os, std::function<ostream& (ostream&)>& s)
{
return s(os);
} 或者将stream作为参数传递给函数:
functionManip(std::cout);关于lambda工作的原因,考虑到lambda的返回类型未定义,并且使用函数指针存在重载:
ostream& operator<< (ostream& ( *pf )(ostream&));lambda可能正在使用结构包装所有东西,并定义operator(),在本例中,将完全像函数指针一样工作。这对我来说是最有可能的解释,希望有人能纠正我,如果我错了。
发布于 2012-10-22 01:00:45
这不是导致错误的原因,但是由于您已经将lambdaManip和functionManip定义为具有返回类型ostream&,所以我认为您忘记了将return stream;添加到两者中。
调用cout << functionManip失败,因为没有定义operator<<(ostream&, std::function<ostream&(ostream&)>。添加一个,调用就会成功。
ostream& operator<<(ostream& stream, function<ostream& (ostream&)>& func) {
return func( stream );
}或者,您也可以将functionManip称为
functionManip( cout );这将在不添加operator<<定义的情况下工作。
至于您关于返回lambda的问题,由于getAdditionFunctor返回的lambda是一个无捕获的lambda,所以它可以隐式转换为一个函数指针。
typedef int(*addition_ptr)(int,int);
addition_ptr getAdditionFunctor()
{
return [] (int x, int y) -> int { return x + y; };
}
auto adder = getAdditionFunctor();
adder(10,20); // Outputs 30发布于 2016-01-20 23:57:37
前面的答案是正确的,但是如果您要在代码中大量使用std::functions和/或lambda作为流操作器,那么您可能只想在全局范围内将以下函数模板定义添加到代码库中:
template<class M>
auto operator<< (std::ostream& os, const M& m) -> decltype(m(os))
{
return m(os);
}那里的尾部返回类型使用表达式SFINAE,因此除非operator<<是一个格式良好的表达式,否则这个特定的operator<<重载甚至不会参与重载解析。(这就是你想要的。)
你甚至可以做这样的事情
template<class T>
auto commaize(const T& t)
{
return [&t](std::ostream& os) -> std::ostream& {
return os << t << ", ";
};
}
int main()
{
std::cout << commaize("hello") << commaize("darling") << std::endl;
}(注意上面的代码中完全缺少任何std::function对象!)尽量避免将lambdas填充到std::function对象中,除非您必须这样做,因为构造std::function对象可能很昂贵;它甚至可能涉及内存分配。)
对于C++17来说,将这个operator<<重载添加到标准库中是有意义的,但我目前还不知道在这方面有任何具体的建议。
https://stackoverflow.com/questions/13003645
复制相似问题