用字符串及其大小折叠表达式
Fold expression with strings and their size
我有这样的 C++14 代码。
我正在更新到 C++17。有没有办法将其重写为折叠表达式?
namespace cat_impl_{
inline size_t catSize(std::string_view const first) {
return first.size();
}
template<typename... Args>
size_t catSize(std::string_view const first, Args &&... args) {
return catSize(first) + catSize(std::forward<Args>(args)...);
}
inline void cat(std::string &s, std::string_view const first) {
s.append(first.data(), first.size());
}
template<typename... Args>
void cat(std::string &s, std::string_view const first, Args &&... args) {
cat(s, first);
cat(s, std::forward<Args>(args)...);
}
}
template<typename... Args>
std::string concatenate(Args &&... args){
// super cheap concatenation,
// with single allocation
using namespace cat_impl_;
size_t const reserve_size = catSize(std::forward<Args>(args)...);
std::string s;
s.reserve(reserve_size);
cat(s, std::forward<Args>(args)...);
return s;
}
是
template <typename... Args>
std::size_t catSize (Args &&... args) {
return (... + std::forward<Args>(args).size());
}
和
template <typename... Args>
void cat (std::string &s, Args ... args) {
(s.append(args.data(), args.size()), ...);
}
或者(更通用,不仅针对 std::string_view
)
template <typename ... Args>
void cat (std::string &s, Args && ... args) {
(s += std::forward<Args>(args), ...);
}
或者,也许,你可以完全避免 cat()
和 catSize()
并简单地写一些东西作为
template <typename... Args>
std::string concatenate (Args &&... args) {
std::string s;
s.reserve((args.size() + ...));
return (s += std::forward<Args>(args), ...);
}
题外话:避免在函数中为同一对象使用双重 std::forward
(参见原始 concatenate()
中 args
的双重 std::forward
)。
这是我想出的:
#include <string>
#include <string_view>
#include <iostream>
template<typename... Args>
std::string concatenate(Args &&... args){
static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
// super cheap concatenation,
// with single allocation
size_t const reserve_size = (std::string_view{ args }.size() + ...);
std::string s;
s.reserve(reserve_size);
(s.append(std::forward<Args>(args)), ...);
return s;
}
template<typename... Args>
std::string const &concatenate(std::string &s, Args &&... args){
static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
// super cheap concatenation,
// sometimes without allocation
size_t const reserve_size = (std::string_view{ args }.size() + ...);
s.clear();
// reserve() will shrink capacity
if (reserve_size > s.capacity())
s.reserve(reserve_size);
(s.append(std::forward<Args>(args)), ...);
return s;
}
int main(){
auto s = concatenate(std::string("Hello"), std::string_view(" "), "world", "!");
std::cout << s << '\n';
}
我认为我不需要 std::forward,因为 std::string::append
无论如何都支持 std::string
、const char *
和 std::string_view
。
我仍然不知道为什么折叠表达式需要放在括号内,但似乎他们需要这样做。
我有这样的 C++14 代码。
我正在更新到 C++17。有没有办法将其重写为折叠表达式?
namespace cat_impl_{
inline size_t catSize(std::string_view const first) {
return first.size();
}
template<typename... Args>
size_t catSize(std::string_view const first, Args &&... args) {
return catSize(first) + catSize(std::forward<Args>(args)...);
}
inline void cat(std::string &s, std::string_view const first) {
s.append(first.data(), first.size());
}
template<typename... Args>
void cat(std::string &s, std::string_view const first, Args &&... args) {
cat(s, first);
cat(s, std::forward<Args>(args)...);
}
}
template<typename... Args>
std::string concatenate(Args &&... args){
// super cheap concatenation,
// with single allocation
using namespace cat_impl_;
size_t const reserve_size = catSize(std::forward<Args>(args)...);
std::string s;
s.reserve(reserve_size);
cat(s, std::forward<Args>(args)...);
return s;
}
是
template <typename... Args>
std::size_t catSize (Args &&... args) {
return (... + std::forward<Args>(args).size());
}
和
template <typename... Args>
void cat (std::string &s, Args ... args) {
(s.append(args.data(), args.size()), ...);
}
或者(更通用,不仅针对 std::string_view
)
template <typename ... Args>
void cat (std::string &s, Args && ... args) {
(s += std::forward<Args>(args), ...);
}
或者,也许,你可以完全避免 cat()
和 catSize()
并简单地写一些东西作为
template <typename... Args>
std::string concatenate (Args &&... args) {
std::string s;
s.reserve((args.size() + ...));
return (s += std::forward<Args>(args), ...);
}
题外话:避免在函数中为同一对象使用双重 std::forward
(参见原始 concatenate()
中 args
的双重 std::forward
)。
这是我想出的:
#include <string>
#include <string_view>
#include <iostream>
template<typename... Args>
std::string concatenate(Args &&... args){
static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
// super cheap concatenation,
// with single allocation
size_t const reserve_size = (std::string_view{ args }.size() + ...);
std::string s;
s.reserve(reserve_size);
(s.append(std::forward<Args>(args)), ...);
return s;
}
template<typename... Args>
std::string const &concatenate(std::string &s, Args &&... args){
static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
// super cheap concatenation,
// sometimes without allocation
size_t const reserve_size = (std::string_view{ args }.size() + ...);
s.clear();
// reserve() will shrink capacity
if (reserve_size > s.capacity())
s.reserve(reserve_size);
(s.append(std::forward<Args>(args)), ...);
return s;
}
int main(){
auto s = concatenate(std::string("Hello"), std::string_view(" "), "world", "!");
std::cout << s << '\n';
}
我认为我不需要 std::forward,因为 std::string::append
无论如何都支持 std::string
、const char *
和 std::string_view
。
我仍然不知道为什么折叠表达式需要放在括号内,但似乎他们需要这样做。