通过移动语义将所有可变参数转换为单个 std::string

Converting all variadic arguments into a single std::string via move semantics

我有一个 class,其中包含如下所示的 lambda 函数:

class Foo {
private:
    inline static std::string text{};

public:
    template<typename...T>
    inline static auto func = [](T&&...args) mutable throw() {
        text += std::string(args...);
    };

    void show() {
        std::cout << text << '\n';
    }
};

我的预期用途是这样的:

int main() {
    Foo bar;
    bar.func<std::string, int, std::string>( "Hello, I am", 39, "years old!");
    bar.show();
    return 0;
}

我希望模板化可变参数 lambda 接受任何类型的基本类型参​​数,例如 stringchar*char[]intfloatdouble 等...并将它们全部转换为单个 std::string 并将存储在 class.

当我 运行 我的代码是这样的:

int main() {
    Foo bar;
    bar.func<string>( "Hello world!");
    bar.show();
    return 0;
}

一切都可以正常编译,但是,当我开始添加各种类型时,例如上面预期用途的示例,它无法编译。 Microsoft Visual Studio 给我一个 C2400 编译器错误:无法从初始化列表转换为 std::string。没有构造函数可以采用源类型,或者构造函数重载决策不明确...

我相信我理解为什么它是模棱两可的,因为这不是问题所在。我的问题是使用 "move semantics or perfect forwarding" 的正确有效方法是什么?我试图避免一堆临时副本。

您可以使用折叠表达式:

template<typename...T>
inline static auto func = [](T&&...args) mutable throw() {
    text += (toString(args) + ...);
};

其中 toString 定义为:

template<class T>
std::string toString(T&& t){
    if constexpr (std::is_arithmetic_v<std::decay_t<T>>)
        return std::to_string(std::forward<T>(t));
    else
        return std::forward<T>(t);
}

您可以扩展 toString 来处理您需要转换为 string 的所有类型。 Demo