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

C++ 当当前字符串的长度与前一个字符串的长度相同时,为什么我的字符串联接程序发出前一个字符串而不是当前字符串,c++,templates,C++,Templates,所以,我有以下花式细绳木工: #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>

所以,我有以下花式细绳木工:

#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();
}
我希望它打印
1234
,但它打印
1212

当我在一行中多次使用我的函数时,当得到的每个字符串都具有相同的长度时,总是会发生同样的情况。在这些情况下,它总是打印序列中的第一个字符串

有人知道为什么会这样吗?

另外,这个问题与
std::cout
优化无关,我也在没有
std::cout
的情况下测试了它

static std::string ret = Internal::stream.str();
。。。只执行一次,因为它是
静态
变量的初始值设定项。只需删除它并从
Internal::stream.str()
返回一个
std::string

这里有一个版本的
Jo
,如果你想获得灵感的话。我保留了静态的
stringstream
,但将其用于
Jo
的所有实例化,但我不确定共享它是否有意义(线程安全问题等)。我会把国旗交给你;)

namespace jou\u详细信息{
std::stringstream;
}
模板
std::string Jo(Args&&…Args){
Jo_detail::stream.str(“”);
//使用虚拟阵列的经典扩展器技巧
使用ex=int[];

(void)ex{0,(void(Jo_detail::stream)您可能应该删除
void*
madness,这毕竟是模板的卖点之一。为什么不简单地使用
operator@Quentin我使用它是因为我看到的唯一其他解决方案是向
Append()传递一组引用
每次都是。我认为它可以让蹩脚的编译器稍微慢一点,但我不确定。@πάνταῥεῖ 你是说每次我需要压缩字符串时都要手动使用stringstream吗?因为使用此函数的代码更紧凑。@HolyBlackCat…显然可靠性更低;-)哎呀。看来我没注意到,因为每种arg类型的组合都有新的实例!在编辑之前,我以为我对模板功夫有所了解。:)顺便说一句,你的解决方案几乎奏效了:
.clear()
清除错误状态,而不是内容。@HolyBlackCat诅咒那个糟糕的前标准接口!现在已经修复:pI个人发现直接使用那个技巧没有什么用处。
模板void run(Fs&&…Fs){using ex=int[];(void)ex{0,(std::forward(Fs)),void(),0)};
助手,然后
运行([&]{Jo_detail::stream@Yakk-ouch。这可能是我更喜欢宏的地方之一。
std::cout << Jo('1','2');
std::cout << Jo('3','4');
static std::string ret = Internal::stream.str();
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();
}