在可变参数模板函数中连接字符串(和数字)

jet*_*ett 13 c++ variadic-functions variadic-templates c++11

我正在尝试编写一个函数,它接受各种字符串或数字(与std::to_string它们一起使用并连接它们.我只使用它来处理字符串,但是我在根据输入作为字符串或数字进行特殊处理时遇到了麻烦.

我的代码被调用如下:

stringer("hello", "world", 2, 15, 0.2014, "goodbye", "world")

这就是我所拥有的:

inline std::string stringer(const std::string &string)
{
    return string;
}

template <typename T, typename... Args>
inline std::string stringer(const std::string &string, T &&val, Args &&...args)
{  
    return stringer(string+std::to_string(val), std::forward<Args>(args)...);
}

template <typename... Args>
inline std::string stringer(const std::string &string, Args &&...args)
{
    return stringer(string, std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

目前它正在打破任何多个字符串添加,除非以下是所有数字(由于to_string).如何根据字符串或数字进行专门化以完成上述工作?谢谢.

Sim*_*ple 15

inline std::string const& to_string(std::string const& s) { return s; }

template<typename... Args>
std::string stringer(Args const&... args)
{
    std::string result;
    using ::to_string;
    using std::to_string;
    int unpack[]{0, (result += to_string(args), 0)...};
    static_cast<void>(unpack);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • @jett它避免了"未使用的变量"警告. (2认同)

Khu*_*hid 12

为什么不使用简单的std :: stringstream?

#include <iostream>
#include <string>
#include <sstream>

template< typename ... Args >
std::string stringer(Args const& ... args )
{
    std::ostringstream stream;
    using List= int[];
    (void)List{0, ( (void)(stream << args), 0 ) ... };

    return stream.str();
}

int main()
{
    auto s = stringer("hello", ' ', 23, ' ', 3.14, " Bye! " );

    std::cout << s << '\n';
}
Run Code Online (Sandbox Code Playgroud)

  • `(/*使用args*/,0)`语法的目的是什么?由于它是逗号运算符,它将为变量参数中的每个项采用表达式的右手部分?基本上创建一个零数组?我理解正确吗? (2认同)
  • @Khurshid为什么它会变成`{(0,((stream << args),0),0)...}`?那里发生了什么? (2认同)

Jan*_*zak 6

还有三种方法可以做到这一点:

  1. 与Khurshid类似,但没有不必要的整数
  2. 类似于Simple和Khurshid,但是建立在较旧的编译器之上
  3. Recurent方式

和代码:

#include <iostream>
#include <sstream>

// First version:
template<typename T>
std::string toString(T value)
{
    std::ostringstream oss;
    oss << value;
    return oss.str();
}

std::string merge(std::initializer_list<std::string> strList)
{
    std::string ret = "";
    for (std::string s : strList) {
        ret += s;
    }
    return ret;
}

template< typename ... Args >
std::string stringer1(const Args& ... args)
{
    return merge({toString(args)...});
}


// Second version:
template< typename ... Args >
std::string stringer2(const Args& ... args)
{
    std::ostringstream oss;
    int a[] = {0, ((void)(oss << args), 0) ... };

    return oss.str();
}


// Third version:
template<typename T>
std::string stringer3(const T& value)
{
    std::ostringstream oss;
    oss << value;
    return oss.str();
}

template<typename T, typename ... Args >
std::string stringer3(const T& value, const Args& ... args)
{
    return stringer3(value) + stringer3(args...);
}

int main()
{
    int a, b;
    std::cout << stringer1("a", 1) << std::endl;
    std::cout << stringer2("b", 2) << std::endl;
    std::cout << stringer3("c", 3) << std::endl;

// Output:
//     a1
//     b2
//     c3
}
Run Code Online (Sandbox Code Playgroud)


Mat*_*att 6

在 C++17 中,我们现在可以使用折叠表达式来简化此操作:

#include <sstream>

// cat - Concatenate values of arbitrary types into a string.
template <typename... Ts>
std::string cat(Ts&&... args) {
  std::ostringstream oss;
  (oss << ... << std::forward<Ts>(args));
  return oss.str();
}
Run Code Online (Sandbox Code Playgroud)