所以,我跟随花式字符串连接器:
#include <iostream>
#include <sstream>
class Internal final
{
~Internal() = delete;
static std::stringstream stream;
static const std::ios_base::fmtflags defflags;
template <typename T, typename ...P> struct Append
{
static void func(const void *const *p)
{
stream << *(T *)*p;
Append<P...>::func(p + 1);
}
};
template <typename T> struct Append<T>
{
static void func(const void *const *p)
{
stream << *(T *)*p;
}
};
template <typename ...P> friend const char *Jo(const P &... p);
};
std::stringstream Internal::stream;
const std::ios_base::fmtflags Internal::defflags = stream.flags();
template <typename ...P> const char *Jo(const P &... p) // 'Join', returned pointer is valid until next call
{
Internal::stream.clear();
Internal::stream.flags(Internal::defflags);
Internal::stream.str("");
const void *const arr[sizeof...(P)] {&p...};
Internal::Append<P...>::func(arr);
static std::string ret = Internal::stream.str();
return ret.c_str();
}
int main()
{
// Test case:
std::cout << Jo("Hello",',',' ',"world!!", 1); // Prints `Hello, world!!1`
return 0;
}
如您所见,Jo(...)
连接所有传递的对象并返回指向结果字符串的指针。这些对象可以包含stringstream
接受的所有类型。此外,此函数接受流操纵器并在每次调用时重置内部stringsteram标志。
它工作正常,但我有一个非常奇怪的问题。
请考虑以下代码:
std::cout << Jo('1','2');
std::cout << Jo('3','4');
我希望它能打印1234
,但会打印1212
。
当我连续多次使用我的函数时,总是会发生同样的事情,当每个结果字符串具有相同的长度时。在这些情况下,它始终按顺序打印第一个字符串。
有谁知道为什么会这样?
P.S。此问题与std::cout
优化无关,我在没有std::cout
的情况下对其进行了测试。
答案 0 :(得分:3)
static std::string ret = Internal::stream.str();
...只执行一次,因为它是static
变量的初始值设定项。只需将其删除,然后从std::string
返回Internal::stream.str()
。
如果你想获取灵感,这是Jo
的版本。我保留了静态stringstream
,但它使Jo
的所有实例化都很常见,但我不确定它是否有意义共享它(线程安全问题等)。我会把旗帜扯到你身上;)
namespace Jo_detail {
std::stringstream stream;
}
template <class... Args>
std::string Jo(Args &&... args) {
Jo_detail::stream.str("");
// Classic expander trick with dummy array
using ex = int[];
(void) ex { 0, (void(Jo_detail::stream << std::forward<Args>(args)), 0)... };
// str() returns a copy anyway
return Jo_detail::stream.str();
}