以下是我生成错误的示例代码:
@font-face {
font-family: 'Glyphicons Halflings';
src: url('../fonts/glyphicons-halflings-regular.eot');
src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
在#include <functional>
using namespace std;
struct S {
S() = default;
S(const S&) = delete;
S(S&&) = default;
S& operator=(const S&) = delete;
S& operator=(S&&) = delete;
};
template <typename F>
void post(F&& func)
{
function<void()> f{forward<F>(func)};
}
int main()
{
S s;
post([s2 = move(s)] { });
}
的lambda中,我使用main()
捕获局部变量s
。在调用post()之前,std::move()
必须已成功移动构建。
但是,在s2
内,post()
不能使用对该lambda类型的右值引用构造。
如果我删除,可以使用此右值引用构建f
,s2 = move(s)
。
为什么添加f
会使lambda不可移动?
这里是尝试coliru的link。
答案 0 :(得分:6)
通过移动捕获,您的lambda不会变得不可移动。但它确实变得不可复制,这是一个问题。
std::function
不支持将提供的仿函数移动到自身,它总是复制。因此,不可复制的lambda(和其他callable)不能与std::function
一起使用。这种限制的原因是该标准要求std::function
是可复制的,如果使用不可复制的可调用对象进行初始化则无法实现。
答案 1 :(得分:2)
问题不在于您的lambda,而在于您的对象不可复制,因为std::function
要求其对象是可复制的,编译器会抱怨。您几乎应该始终遵循rule-of-zero。
通常:
shared_ptr
)。示例:
#include <iostream>
#include <type_traits>
struct S
{
S() {
std::cout << "ctor" << '\n';
}
~S() noexcept {
std::cout << "dtor" << '\n';
}
S(const S&) {
std::cout << "copy ctor\n";
}
S(S&&) noexcept noexcept {
std::cout << "move ctor\n";
}
S& operator= (const S&) {
std::cout << "copy aop\n";
}
S& operator= (S&&) noexcept {
std::cout << "move aop\n";
}
};
template <typename T>
void getTraits()
{
std::cout << std::boolalpha
<< "trivially_copy_constructible? "
<< std::is_trivially_copy_constructible_v<T>
<< "\ntrivially_move_constructible? "
<< std::is_trivially_move_constructible_v<T> << '\n' ;
}
int main()
{
S s ;
const S cs;
{
std::cout << "capture by value\n" ;
//auto closure = [s = std::move(s)] {} ; // S::move construct // 1.
//auto closure = [cs = std::move(cs)] {} ; // S::copy construct // 2.
//const auto closure = [s = std::move(s)] {} ; // S::move construct // 3.
const auto closure = [cs = std::move(cs)] {} ; // S::copy construct // 4.
getTraits<decltype(closure)>();
const auto copy_constructed = std::move(closure);
const auto move_constructed = std::move(closure);
}
{
std::cout << "\ncapture by reference\n";
const auto closure = [&s] {};
getTraits<decltype(closure)>();
}
}
一次取消注释1、2、3、4,然后检查输出。请记住,std::move
只是将一个对象变成右值引用。