将多个字符串连接在一起在 C++ 中具有不同的复杂性,具体取决于它是如何完成的。我相信你想到的情况是:
string result = string("Hello, ") + username + "! " +
"Welcome to " + software_product + ".";
连接 6 个字符串。第一个字符串被复制 5 次,第二个字符串被复制 4 次,以此类推。正如Leonid Volnitsky 在他的回答中指出的那样,这个 Θ(NM) 的确切界限,其中 M 是连接操作的数量,N 是被连接的字符串的总长度。当 M
表达式模板可以帮助加速这个用例,尽管它会导致 C++11 中的 auto 和 decltype 类型推断以及 C++98 中的模板类型推断出现问题。所有这些都会推断出
的类型
auto result = string("Hello, ") + username + "! " +
"Welcome to " + software_product + ".";
成为用于使表达式模板魔术发生的延迟评估字符串模板类型。表达式模板不是一个好主意的其他原因包括 Leonid Volnitsky 的关于减慢编译时间的回答。它可能还会增加编译后的二进制文件的大小。
相反,C++ 中还有其他解决方案可用于获得 Θ(N) 连接:
string result = "Hello, ";
result += username;
result += "! ";
result += "Welcome to ";
result += software_product;
result += ".";
在这个版本中,字符串被原地修改,虽然已经复制到result的数据有时需要重新复制,但C++字符串通常实现为dynamic arrays,它以指数方式分配新空间,因此每个新字符的插入需要分摊的常数时间,导致重复连接的整体 Θ(N) 行为。
以下是做同样事情的一种方式,几乎在一条线上。它在内部使用相同的原理,但也支持使用
stringstream result;
result << "Hello, " << username << "! " << "Welcome to " << software_product
<< ".";
// do something with result.str()
最后,C++ 标准库不包含此功能,但可以定义以下函数,其中包含一些字符串流魔术。该实现留给读者作为练习。
template <typename... Items>
std::string concat(std::string const& a, std::string const& b, Items&&... args)
然后您可以调用concat 在 O(N) 时间内在一行上重复连接:
string result = concat("Hello, ", username, "! ", "Welcome to ",
software_product, ".");
据推测,所有这些都是比通过创建表达式模板类型来搞乱类型推断更好的解决方案。