【发布时间】:2017-06-14 17:32:00
【问题描述】:
在this answer 他们建议使用以下代码:
#include <iostream>
template <typename F>
class Finally {
F f;
public:
template <typename Func>
Finally(Func&& func) : f(std::forward<Func>(func)) {}
~Finally() { f(); }
Finally(const Finally&) = delete;
Finally(Finally&&) = delete;
Finally& operator =(const Finally&) = delete;
Finally& operator =(Finally&&) = delete;
};
template <typename F>
Finally<F> make_finally(F&& f)
{
return Finally<F>{ std::forward<F>(f) }; // This doesn't compile
//This compiles: return { std::forward<F>(f) };
}
int main()
{
auto&& doFinally = make_finally([&] { std::cout<<", world!\n"; });
std::cout << "Hello";
}
作者链接到一个使用 Clang++/G++ 编译的演示。但是,此代码在 MSVC++2017 中无法为我编译。
错误信息是:
source_file.cpp(20): error C2280: 'Finally<main::<lambda_9000fb389e10855198e7a01ce16ffa3d>>::Finally(Finally<main::<lambda_9000fb389e10855198e7a01ce16ffa3d>> &&)': attempting to reference a deleted function
source_file.cpp(12): note: see declaration of 'Finally<main::<lambda_9000fb389e10855198e7a01ce16ffa3d>>::Finally'
source_file.cpp(26): note: see reference to function template instantiation 'Finally<main::<lambda_9000fb389e10855198e7a01ce16ffa3d>> make_finally<main::<lambda_9000fb389e10855198e7a01ce16ffa3d>>(F &&)' being compiled
with
[
F=main::<lambda_9000fb389e10855198e7a01ce16ffa3d>
]
那么return { std::forward<F>(f) }; 和return Finally<F>{ std::forward<F>(f) }; 有什么区别,一个编译,另一个不编译?
【问题讨论】:
-
auto&&应该被 MSVC 支持。 -
Finally<F> make_finally(F&& f)不应该是Finally<std::decay_t<F>> make_finally(F&& f)吗? -
为什么要用 Clang 编译?
make_finally的返回想要调用Finally的(已删除)移动构造函数。如果事件被优化,它应该仍然需要可用。 -
@1201ProgramAlarm 如果
make_finally是 RVO 的候选者,由于 C++17 保证 RVO,你不需要移动构造函数 IIRC -
人!这里没有移动。
make_finally()直接在返回对象中创建一个Finally<F>,然后绑定到引用doFinally。即使没有新的值类别,即使有-fno-elide-constructors,也不会发生任何移动。
标签: c++ c++14 visual-studio-2017 c++17 auto