我试图弄清楚如何使用C++17折叠表达式折叠可变参数模板包的一部分。
这可以很容易地用这样的代码完成(只是一个例子):
std::string result;
template<class... Strings>
ConcatString(Strings&... strs)
{
(ConcatString(strs), ...);
}
template <class String>
void ConcatString(String& str)
{
result += str + "_"
}
然后我们就可以那样执行了
std::string s1 = "s1", s2 = "s2", s3 = "s3";
ConcatString(s1, s2, s3);
// result == "s1_s2_s3_"
正如你所看到的,最后一个分隔符有一个问题。有没有什么方法可以避免这个问题而不需要运行时检查?我可以想象的一个解决方案是只折叠(N - 1)个args并“手动”concat最后一个。
3条答案
按热度按时间dxxyhpgq1#
您可以递归调用
ConcatString
并使用constexpr if来避免运行时检查qzwqbdag2#
有没有可能用C++17的fold表达式只折叠包的一部分?
不,一个折叠表达式将折叠整个包。然而,我们可以做一些技巧来实现我们所需要的。
在这里,您的
Concat
函数可以简化为使用单个二进制折叠。用法:
输出:
项目a
a、B
a、B、c
这里的技巧是,我们将参数包分成一个单一的“头”(
str
)和一个可变的“尾”(strs
)。这样,我们让函数参数列表从包中取出第一个元素。(很多C11风格的模板元编程都使用了这个技巧)。另一种方法是为我们的参数包创建一组索引0、1、...、N,然后对于折叠逻辑,我们可以为第0个、第N个甚至是任意元素。你可以在pretty print tuple问题中找到各种各样的这种方法。在C20中,感谢C++中的模板lambda我们可以把所有的逻辑移到一个方法中,就像这样:
Demo 2
这个丑陋的语法是我创建了一个lambda,并在一个语句中调用它。你可以通过
std::invoke
调用它来提高它的可读性。请注意,我们对索引进行了检查,以确定是否打印分隔符。
让我们使用索引检查技巧,只使用分隔符连接每一个其他的:
现在
std::cout << ConcatEveryOther(",", "a", "b", "c", "d", "e", "f", "g") << std::endl;
将给予如下输出a、bc、de、fg
∮ ∮ ∮ ∮ ∮
des4xlb03#
不如这样:
编辑:我把函数做得更简单了: