C++ 11の機能を使用してカスタムストリームマニピュレータを簡単に作成しようとしています。ラムダ関数をマニピュレータとして使用できますが、std::function<ostream&(ostream&)>
では使用できません。std :: functionをカスタムストリームマニピュレータとして使用する
ここでのコードは、煮詰めています:
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>&)>]'
これはなぜ失敗しない:
#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
文は次のように失敗しますか?私はcygwin gcc 4.5.3を使用しています。
効率的な問題のため、どこでもstd::function
を使用しているとは言いませんが、私は尋ねています。しかし、私はラムダ関数を返す関数を書くことを望んでいて、std::function
を使わずにその方法を知らないといけません。たとえば、次のようなものは素晴らしいでしょう。
auto getAdditionFunctor();
auto getAdditionFunctor() {
return [] (int x, int y) { return x + y };
};
...明らかに動作しません。動作する別の構文がありますか?私はそれが何であるか想像することができないので、私はstd::function
とつかまっているかもしれません。
私に2番目の質問に対する解決策があった場合、最初の質問は疑問に思うでしょう。
ありがとうございます。
定義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
があります。私はこれが私のプロジェクトで実際にソリューションを実装しようとしていることを発見しました。
これらのマニピュレータに「リターン」を残しておいたのですか? –
私はそれらが暗示されていることを読んでいましたが、それらを追加することは助けになりません。この場合、私は彼らが返品で読みやすいと思っていますが、彼らは合法的です。結局、私が 'cout << functionManip; 'をコメントアウトすれば、すべての動作はうまく動作します。 –
@EdKrohne: 'return'は**ここではオプションではありません** - あなたのラムダは、他の関数と同様に、' void'以外の戻り値型を持ち、値を返さないことでUBを呼び出します。 §6.6.3/ 2: "*関数の終わりからの流れは、値なしの' return'と等価です;これは値を返す関数では未定義の振る舞いになります。* "うまく動作するように見えるのは、 UBの – ildjarn