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

如果你愿意使用一些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
#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

使用do { } while (false)idiom 使几行宏。

#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

将 Nicol 的答案恢复为迄今为止最好的答案:

您当前的问题是所有各种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 回答
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&而不是临时类型,以便可以直接与用户定义的输出运算符一起使用。为此,您应该插入其中一种直接支持的类型,该类型std::ostream没有任何效果但返回一个std::ostream&,例如:

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