首页 > 解决方案 > 通过移动语义将所有可变参数转换为单个 std::string

问题描述

我有一个包含 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 接受任何类型的基本类型的参数,例如string, char*, char[], int, float,double等...并将它们全部转换为单个 std::string 将存储在类中.

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

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

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

我相信我理解为什么它是模棱两可的,因为这不是问题所在。我的问题是使用“移动语义或完美转发”的正确有效方式是什么?我试图避免一堆临时副本。

标签: stringlambdac++17movevariadic

解决方案


您可以使用折叠表达式:

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. 演示


推荐阅读