【发布时间】:2019-09-23 08:37:41
【问题描述】:
在下面的程序中,当mutable没有被使用时,程序编译失败。
#include <iostream>
#include <queue>
#include <functional>
std::queue<std::function<void()>> q;
template<typename T, typename... Args>
void enqueue(T&& func, Args&&... args)
{
//q.emplace([=]() { // this fails
q.emplace([=]() mutable { //this works
func(std::forward<Args>(args)...);
});
}
int main()
{
auto f1 = [](int a, int b) { std::cout << a << b << "\n"; };
auto f2 = [](double a, double b) { std::cout << a << b << "\n";};
enqueue(f1, 10, 20);
enqueue(f2, 3.14, 2.14);
return 0;
}
这是编译器错误
lmbfwd.cpp: In instantiation of ‘enqueue(T&&, Args&& ...)::<lambda()> [with T = main()::<lambda(int, int)>&; Args = {int, int}]’:
lmbfwd.cpp:11:27: required from ‘struct enqueue(T&&, Args&& ...) [with T = main()::<lambda(int, int)>&; Args = {int, int}]::<lambda()>’
lmbfwd.cpp:10:2: required from ‘void enqueue(T&&, Args&& ...) [with T = main()::<lambda(int, int)>&; Args = {int, int}]’
lmbfwd.cpp:18:20: required from here
lmbfwd.cpp:11:26: error: no matching function for call to ‘forward<int>(const int&)’
func(std::forward<Args>(args)...);
如果没有mutable,我无法理解为什么参数转发会失败。
此外,如果我传递带有字符串作为参数的 lambda,则不需要 mutable 并且程序可以正常工作。
#include <iostream>
#include <queue>
#include <functional>
std::queue<std::function<void()>> q;
template<typename T, typename... Args>
void enqueue(T&& func, Args&&... args)
{
//works without mutable
q.emplace([=]() {
func(std::forward<Args>(args)...);
});
}
void dequeue()
{
while (!q.empty()) {
auto f = std::move(q.front());
q.pop();
f();
}
}
int main()
{
auto f3 = [](std::string s) { std::cout << s << "\n"; };
enqueue(f3, "Hello");
dequeue();
return 0;
}
为什么在 int double 的情况下需要 mutable 而在 string 的情况下不需要?这两者有什么区别?
【问题讨论】:
-
顺便说一句,在第二个示例中,您不是转发
std::string,而是转发const char*。函数采用什么类型并不重要,而是将什么类型的参数传递给enqueue。我的猜测是,从一开始就是const的论点会有所不同,但我不确定如何。 -
确实,it does fail 如果你做到了
enqueue(f3, std::string("Hello")); -
...是,或
"Hello"s(使用字符串文字) -
@IgorTandetnik 方向是对的:如果您传递
const参数,错误就会消失。参见例如godbolt.org/z/EdY4Mn,我刚刚介绍了一些空类Foo。如果你去掉Foo的常量,编译失败。不过还是不知道为什么…… -
意识到使用
std::forward<const Args>也可以修复编译错误可能很有启发性(尽管毫无意义)。
标签: c++ c++11 lambda language-lawyer