为什么当当前字符串的长度与前一个字符串的长度相同时,我的字符串连接程序会发出前一个而不是当前字符串
Why my string joiner emits previous string instead of the current one when the length of a current string is same as the length of a previous one
因此,我有以下奇特的字符串连接程序:
#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
接受的所有类型。此外,此函数接受流操纵器,并在每次调用时重置内部stringstram标志。
它运行良好,但我有一个非常奇怪的问题。
考虑以下代码:
std::cout << Jo('1','2');
std::cout << Jo('3','4');
我希望它能打印1234
,但它打印1212
。
当我在一行中多次使用函数时,当得到的每个字符串都有相同的长度时,总是会发生同样的情况。在这些情况下,它总是打印序列中的第一个字符串。
现场观看。
有人知道为什么会这样吗
附言:这个问题与std::cout
优化无关,我也在没有std::cout
的情况下测试了它。
static std::string ret = Internal::stream.str();
仅执行一次,因为它是static
变量的初始值设定项。只需移除它并从Internal::stream.str()
返回一个std::string
。
这是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();
}