0

std :: ostream&operator <<連結オブジェクトのリストを唯一の引数として取り、統合された文字列を単一のstd::stringオブジェクトとして関数に渡すマクロを作成したいと思います。統合された文字列を関数に渡す機能が重要です。以下の例では、マクロをに定義するだけで例自体が機能するように書き直すことができることを認識していますERR_MSG(inputs) std::cout << "ERROR: " << inputsが、出力をstd :: coutに送信することは目標ではなく、例として選択したテストの目的にすぎません。

GCC 4.1.2(Red Hat 4.1.2-52)を使用していますが、アップグレードすることはできません。これが私が試したものの非常に要約されたバージョンです:

#include <sstream>
#include <iostream>

#define ERR_MSG(inputs) errMsg(std::ostringstream().str())           // 1
#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2
<aReturnType> errMsg(const std::string& msg)                                 // use with 1 & 2
{
    std::cout << "\nERROR: " << msg << "\n\n";
    return <someObjectCreatedBasedOnTheInput>;
}

#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs)         // 3
<aReturnType> errMsg(const std::ostringstream& msg)                           // use with 3
{
    std::cout << "\nERROR: " << msg.str() << "\n\n";
    return <someObjectCreatedBasedOnTheInput>;
}

int main()
{
    ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
}

マクロ#1はコンパイルされますが、もちろんメッセージには「」しか出力されません。マクロ2と3はどちらもコンパイルされず、次のエラーが発生します。

#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2
error: ‘struct std::basic_ostream<char, std::char_traits<char> >’ has no member named ‘str’

#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs)         // 3
no matching function for call to ‘errMsg(std::basic_ostream<char, std::char_traits<char> >&)’
    note: candidates are: char* errMsg(const std::string&)
    note:                 char* errMsg(const std::ostringstream&)

マクロなしでこれを書き直す方法には興味がありません。自分でも簡単にできます。

===更新:===実際のユースケースでは、マクロによって呼び出された関数が、マクロの呼び出し元によって使用される可能性のあるオブジェクトを返すことを忘れました。これにより、単一の式で実装できないマクロ実装が無効になり、その結果、マクロによって呼び出された関数の戻り型が無効になります。マクロの「何もしない」実装(リリースビルドの場合)は、「入力」が何であるかに関係なく、空のstd::stringを関数に渡すだけです。先に言及しなかったことをお詫びします。

4

6 に答える 6

3

現在の問題は、さまざまな関数のすべてが、ではなく、をoperator<<返すことです。あなたは簡単なキャストでそれを解決することができます:ostream&ostringstream&

#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str())

は一時的flushなものなので必要です。std::ostringstream()したがって、左辺値参照をとる関数を呼び出すことはできません(例:) std::ostream&。ほとんどoperator<<のバリアントのように機能します。flush呼び出しが行うのは、左辺値参照としてポインターを返すことだけthisです。

于 2012-09-28T21:37:58.663 に答える
1
#include <sstream>
#include <iostream>

#define ERR_MSG(inputs) errMsg(std::ostringstream().flush()<<inputs)
int errMsg(std::ostream& os)
{
    std::ostringstream& oss(static_cast<std::ostringstream&>(os));
    const std::string& str(oss.str());
    std::cout << "\nERROR: " << str << "\n\n";
    return str.length();
}

int main()
{
    int i = ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
   std::cout << i << "\n";
}
于 2012-09-28T22:12:24.893 に答える
1

GCC拡張機能を使用する場合、ブロック内のマクロ内で実際のostringstreamを宣言して、キャストせずに.str()メソッドを使用できるようにすることができます。

#define ERR_MSG(inputs) \
    do { std::ostringstream _s_; _s_<<inputs;errMsg(_s_.str()); } while(false)

デモ: http: //ideone.com/clone/y56lc

于 2012-09-28T21:36:53.573 に答える
1

イディオムを使用do { } while (false)して、数行のマクロを作成します。

#define ERR_MSG(inputs) \
  do { \
      std::ostringstream osERR_MSG; \
      osERR_MSG << inputs; \
      errMsg(osERR_MSG.str()); \
  } while (false)


int main() {
   if (1) ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
   else return 0;
}

私がそのような奇妙な名前を付けた理由は、次のosERR_MSGようなケースをできるだけ避けるためです。

int osERR_MSG = 7;
ERR_MSG(osERR_MSG);
于 2012-09-28T21:52:58.617 に答える
0

私は作成しませんstd::ostringstreamが、から派生したクラスのデストラクタから呼び出される関数を持っていますstd::ostream。このアプローチの例を次に示します。

#include <sstream>
#include <iostream>

void someFunction(std::string const& value)
{
    std::cout << "someFunction(" << value << ")\n";
}

void method(std::string const& value)
{
    std::cout << "method(" << value << ")\n";
}

class FunctionStream
    : private virtual std::stringbuf
    , public std::ostream
{
public:
    FunctionStream()
        : std::ostream(this)
        , d_function(&method)
    {
    }
    FunctionStream(void (*function)(std::string const&))
    : std::ostream(this)
    , d_function(function)
    {
    }
    ~FunctionStream()
    {
        this->d_function(this->str());
    }
private:
    void (*d_function)(std::string const&);
};

int main(int ac, char* av[])
{
    FunctionStream() << "Hello, world: " << ac;
    FunctionStream(&someFunction) << "Goodbye, world: " << ac;
}

使用例ではマクロを使用していませんが、これは上記のの使用に簡単にラップできますFunctionStream()。マクロでは、マクロのユーザーにstd::ostream&表示される型が一時的な型ではなく型であることを確認して、ユーザー定義の出力演算子で直接使用できるようにする必要があることに注意してください。このためには、直接サポートされているタイプの1つを挿入する必要があります。std::ostreamこれは、効果はありませんがstd::ostream&、たとえば次のように返されます。

#define SomeMacro(output) FunctionStream(&someFunction) << "" << output
于 2012-09-28T21:45:46.277 に答える
0

ニコルの答えをこれまでで最高のものとして復活させる:

現在の問題は、さまざまな関数のすべてが、ではなく、をoperator<<返すことです。あなたは簡単なキャストでそれを解決することができます:ostream&ostringstream&

#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str())

もちろん、これにはまだ問題があります(ここにあるすべての答えのように)

ERR_MSG(x ? "x is true" : "x is false")

奇妙で紛らわしい方法で誤動作します。

于 2012-09-28T22:18:52.870 に答える