我知道这是一个老问题,但我有一个类似的问题,以上答案都不适合我的所有需求,所以我将在这里发布我的解决方案。
我的要求是:
- 我需要一个能够使用任何可迭代容器和任何数据类型的通用解决方案,当然对于自定义数据类型,您必须提供合适的
operator<<()
- 我需要一种简单的方法来对数据应用转换(例如,默认情况下,
int8_t 和 uint8_t 被 chars 处理为 std::stringstream:也许这是你想要的,也许不是,所以我希望能够做出这样的选择)
- 我希望能够将分隔符指定为字符串文字,但也接受
chars 和std::strings
- 我喜欢有添加封闭字符的能力,但这可能是非常个人的品味
这假设 C++11。
我选择使用std::stringstream,因为它实现了一种标准但仍可自定义的方式来将某些内容转换为字符串。
任何 cmets 都非常受欢迎。
#include <iterator>
#include <sstream>
#include <string>
#include <iostream> // used only in main
#include <vector> // used only in main
template< typename T >
typename std::iterator_traits< T >::value_type
identity(typename std::iterator_traits< T >::value_type v) {
return v;
}
template< typename T > using IdentityType = decltype(identity< T >);
template< class InItr,
typename StrType1 = const char *,
typename StrType2 = const char *,
typename StrType3 = const char *,
typename Transform = IdentityType< InItr > >
std::string join(InItr first,
InItr last,
StrType1 &&sep = ",",
StrType2 &&open = "[",
StrType3 &&close = "]",
Transform tr = identity< InItr >) {
std::stringstream ss;
ss << std::forward< StrType2 >(open);
if (first != last) {
ss << tr(*first);
++first;
}
for (; first != last; ++first)
ss << std::forward< StrType1 >(sep) << tr(*first);
ss << std::forward< StrType3 >(close);
return ss.str();
}
int main(int argc, char** argv) {
const std::vector< int > vec{2, 4, 6, 8, 10};
std::cout << join(vec.begin(), vec.end()) << std::endl;
std::cout << join(vec.begin(), vec.end(), "|", "(", ")",
[](int v){ return v + v; }) << std::endl;
const std::vector< char > vec2{2, 4, 6, 8, 10};
std::cout << join(vec2.begin(), vec2.end()) << std::endl;
std::cout << join(vec2.begin(), vec2.end(), "|", "(", ")",
[](char v){ return static_cast<int>(v); }) << std::endl;
}
输出类似:
[2,4,6,8,10]
(4|8|12|16|20)
[<unprintable-char>,<unprintable-char>,<unprintable-char>,
]
(2|4|6|8|10)