#include <iostream>
#include <thread>
#include <utility>
using namespace std;
template <typename T>
class OnExitImpl : private T
{
public:
template <typename Y>
OnExitImpl(Y&& todo) : T(std::forward<Y>(todo)), _doIt(true) {}
OnExitImpl(OnExitImpl&& other) : T(std::move(static_cast<T&>(other))), _doIt(other._doIt)
{
other._doIt = false;
}
~OnExitImpl()
{
if (_doIt)
{
(*this)();
}
}
void Cancel()
{
_doIt = false;
}
OnExitImpl& operator=(OnExitImpl&& other)
{
this->T::operator=(std::move(static_cast<T&>(other)));
_doIt = other._doIt;
other._doIt = false;
}
private:
bool _doIt;
};
template <typename T>
OnExitImpl<T> OnExit(T action)
{
return OnExitImpl<T>(std::move(action));
}
int FetchMultithreaded(int stmt)
{
auto onExit = OnExit([&](){ cout << stmt << endl; });
std::thread fetchThread([&]()
{
auto onExit = OnExit([&](){ cout << stmt << endl; });
});
return 0;
}
int main()
{
return FetchMultithreaded(0);
}
当我在 Visual Studio 2013 中编译它时,出现以下错误:
1>Source.cpp(9): error C2516: 'T' : is not a legal base class
1> Source.cpp(55) : see declaration of 'T'
1> Source.cpp(55) : see reference to class template instantiation 'OnExitImpl<void (__cdecl *)(void)>' being compiled
当我在 http://ideone.com/O6I9nj 上尝试时,我得到了大量关于 std::forward 的错误,不确定那里发生了什么。不确定使用的是哪个编译器。
Visual Studio 错误消息让我认为这是一个编译器错误,因为它似乎将 lambda 视为函数指针......
编辑:将模板参数添加到 std::forward 后,它现在可以在 Ideone 上编译(但由于其他原因不链接),但不会对 Visual Studio 进行任何更改。这让我怀疑这是一个编译器错误。
编辑 2:无论如何,我已经通过添加以下代码解决了这个问题:
template <typename Ret>
struct FnPtrWrapper
{
FnPtrWrapper(Ret (*fn)(void)) : _fn(fn)
{
assert(fn);
}
Ret operator()() const
{
return (*_fn)();
}
private:
Ret (*_fn)(void);
};
template <typename Ret>
OnExitImpl<FnPtrWrapper<Ret>> OnExit(Ret(*fn)(void))
{
return OnExitImpl<FnPtrWrapper<Ret>>(fn);
}
这似乎很奇怪,这修复了它,因为我使用的 lambda 触发了错误实际上捕获了一个函数参数,因此不应该转换为函数指针......
最佳答案
这是我认为以前(在 SO 上)遇到过的 VC++ 错误。最小复制样本:
#include <type_traits>
template <typename T>
struct B { static_assert(std::is_class<T>::value, "T not a class"); }; // (2)
int main()
{
[]{
auto a = []{};
static_assert( std::is_class<decltype(a)>::value, "Not a class" ); // (1)
B<decltype(a)> b;
}();
}
Demo on rextester's VC++ 。
请注意代码必须如何在外部 lambda 内为 才能发生错误。
虽然 (1) 成功,但
b
的声明导致 (2) 失败这表明模板参数
decltype(a)
表示函数指针类型,同时也表示类类型。关于c++ - C2516 从 Visual Studio 2013 中的 lambda 继承时出错,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28284196/