lambda(参数)中的 const 限定符,用于带有 std::sregex_token_iterator 的 std::transform
Posted
技术标签:
【中文标题】lambda(参数)中的 const 限定符,用于带有 std::sregex_token_iterator 的 std::transform【英文标题】:const qualifier in lambda(parameter) for std::transform with std::sregex_token_iterator 【发布时间】:2019-07-23 10:27:48 【问题描述】:我回答了关于 SO (this) 的问题,以解析一些字符串并产生特定的输出。为此,我使用了std::transform
。对于unary_op
,我使用了 lambda。 lambda 的参数显然需要为const
。强迫我引入一个额外的局部变量。如果不使用const
,我会收到语法错误(编译器:MS VS19)。
我检查了 cppreference here 上的 std::transorm
文档。
unary_op - 将应用的一元操作函数对象。
函数的签名应该等同于:
Ret fun(const Type &a);
签名不需要有 const &。 类型 Type 必须使得 InputIt 类型的对象可以被取消引用,然后隐式转换为 Type。 Ret 类型必须使得 OutputIt 类型的对象可以被取消引用并分配一个 Ret 类型的值。
我不完全理解这一点。我是否需要使用const&
参数。这是std::sregex_token_iterator
实施的结果吗?我试图了解std::regex_token_iterator 的文档。抱歉,我不明白取消引用此迭代器是否可以转换为 std::string。
.
我在这里走错了吗?或者有人可以解释一下为什么它会这样吗?或者有没有我看不到的解决方案?
.
示例代码:
#include <string>
#include <iostream>
#include <regex>
#include <iterator>
int main()
// 1. This is the string to convert
std::string line("Hi there buddy");
// 2. We want to search for complete words
std::regex word("(\\w+)");
// 3. Transform the input string to output lines
std::transform(
std::sregex_token_iterator(line.begin(), line.end(), word, 1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[](const std::string & w) // ******* Must be const *******
static int i = 1;
std::string s = w;
s[0] = ::toupper(s[0]);
return std::string("List[") + std::to_string(i++) + "]=" + s;
);
return 0;
【问题讨论】:
不标记为const
是不行的,只要你没有实际修改它,但它确实应该是const
,因为你没有修改它无论如何。
我想修改它。首字母大写。所以,我介绍了一个临时的。我想避免的。
我的意思是,你不能修改w
。复制它然后修改副本不算作修改参数。
【参考方案1】:
我不完全理解这一点。我是否需要使用 const& 参数
关键是你不应该改变输入迭代器指向的值,只能从中读取。这是一个输入迭代器,而不是一个输出迭代器。
正如您链接的 std::transform
文档所说:
unary_op 和 binary_op 不能有副作用。
改变输入将被视为副作用。运算符应该接受旧值并返回新值,仅此而已。
是否需要使用 const& 参数
不可以,但您不能改变原始对象。文档明确说明
签名不需要有 const &。 类型 Type 必须使得 InputIt 类型的对象可以被取消引用,然后隐式转换为 Type。
所以,你可以采取隐式复制
[](std::string s) /* no need to copy from w explicitly */
或使用std::string_view
(implicit conversion 来自std::string
)
[](std::string_view v) /* ... */
【讨论】:
输入迭代器。这是重点。这就是原因的解释。而且我习惯于在 lambdas 中引用参数,以至于我没有采用按值传递的解决方案。逆天。谢谢【参考方案2】:我是否需要使用
const&
参数?
您不需要一个,但拥有一个通常是有意义的。首先,考虑到std::transform
要求unary_op
没有任何 副作用。这意味着您无论如何都不能更改参数。接下来,请注意unary_op
的参数是取消引用的输入迭代器,如您所知。这可以是左值,也可以是右值,具体取决于您传递给std::transform
的输入序列。在您的情况下,取消引用 std::regex_token_iterator
会产生一个 std::sub_match
,它具有到底层字符串类型 (this one) 的隐式转换运算符 - 对于您来说,这又是 std::string
。现在这是一个右值,一个右值只能绑定到一个const
限定的引用(这就是为什么删除const
并保留该引用不能编译的原因)。你还有另一个理由来输入const
。
总而言之,您有以下选择:
通过const
参考。这应该是您使用 std::transform
时的默认设置。
按值传递。如果您想更改输入序列的副本以进行进一步处理,请执行此操作。这不会导致副作用,因此是允许的。
如果取消引用迭代器会产生一个临时值,您还可以传递一个右值引用(在您的情况下为std::string&&
)。对其进行修改或移动构造是合法的,因为这不会影响std::transform
输入序列,而只会影响临时序列。
在您的情况下,我会按值传递并删除副本 std::string w = v
。这将构造 lambda 操作的 std::string
对象(无副本)。
【讨论】:
副作用和价值传递。比恩x。你和用户“没用”给出了很好的解释。两者都有。以上是关于lambda(参数)中的 const 限定符,用于带有 std::sregex_token_iterator 的 std::transform的主要内容,如果未能解决你的问题,请参考以下文章
将 'const QVariant' 作为 'this' 参数传递会丢弃限定符 [-fpermissive]
错误:将“const SunscreenSPF”作为“this”参数传递会丢弃限定符问题
C++ 错误 - 将 'const Dataset<double>' 作为 'this' 参数传递会丢弃限定符 [-fpermissive]