为什么当当前字符串的长度与前一个字符串的长度相同时,我的字符串连接程序会发出前一个而不是当前字符串

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

本文关键字:字符串 一个 程序 为什么 我的 连接      更新时间:2023-10-16

因此,我有以下奇特的字符串连接程序:

#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();
}
相关文章: