需要一个宏来从 std::ostringstream 和 << arg 列表创建 std::string
Need a macro to create a std::string from a std::ostringstream and a << arg list
我想写一个宏,它的唯一参数是std::ostream&运算符<lt;连接对象,并将合并字符串作为单个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 << "nn";
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() << "nn";
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::字符串,而不管"输入"是什么。很抱歉之前没有提到。
您当前的问题是所有各种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
指针作为左值引用。
#define ERR_MSG(inputs)
do { std::ostringstream _s_; _s_<<inputs;errMsg(_s_.str()); } while(false)
演示:http://ideone.com/clone/y56lc
使用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);
#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 << "nn";
return str.length();
}
int main()
{
int i = ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
std::cout << i << "n";
}
我不会创建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
将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")
会以一种奇怪和令人困惑的方式表现不端。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 错误:调用"std::vector<:vector<int>>::p ush_back(std::vector<std::__cxx11::basic_string<
- C 建造者Clang STD :: Sill,找不到超载的操作员&lt;
- 为什么STD :: MAP需要操作员&lt;以及我如何写一个
- std::vector::reserve(未知m),我知道m<<;N(通常)并且知道N
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- C++运算符<<调用::ostream而不是std::osttream
- 是std :: set&lt; std :: future&gt;不可能存在
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- BOOST ::变体无法解决运算符&lt;&lt;对于STD :: Ostream
- C++重载<<具有typedef'd std::vector
- 以x的倍数填充前导零,使用std::cout<<std::十六进制
- 错误:没有匹配'运算符<<"在'std::cout
- std::pair的默认构造函数<>将基本类型(int等)设置为零
- std::ostream&operator< & lt; (std:: ostream&压力,压力& &;val)
- 将std::endl传递给std::operator<<
- std::映射<>或std::vector<>在处理大型标志集时
- 重载& lt; & lt;使用命名空间std