C2516 在 Visual Studio 2013 中从 lambda 继承时出错
C2516 Error in inheriting from a lambda in Visual Studio 2013
#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 上编译(但由于其他原因 link 不编译),但不会为 [=29] 更改任何内容=].这让我怀疑这是一个编译器错误。
编辑 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 实际上捕获了一个函数参数,因此不应该转换为函数指针...
这是一个 VC++ 我相信以前遇到过的错误(在 SO 上)。最小复制样本:
#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;
}();
}
请注意代码必须在外部 lambda 中 才会发生错误。
虽然 (1) 成功,但 b
的声明导致 (2) 失败
source_file.cpp(4) : error C2338: T not a class
source_file.cpp(11) : see reference to class template 'B<void (__cdecl *)(void)>
' being compiled
这表明模板参数 decltype(a)
表示指向函数的指针类型,同时也表示 class 类型。
#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 上编译(但由于其他原因 link 不编译),但不会为 [=29] 更改任何内容=].这让我怀疑这是一个编译器错误。
编辑 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 实际上捕获了一个函数参数,因此不应该转换为函数指针...
这是一个 VC++ 我相信以前遇到过的错误(在 SO 上)。最小复制样本:
#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;
}();
}
请注意代码必须在外部 lambda 中 才会发生错误。
虽然 (1) 成功,但 b
的声明导致 (2) 失败
source_file.cpp(4) : error C2338: T not a class
source_file.cpp(11) : see reference to class template 'B<void (__cdecl *)(void)>
' being compiled
这表明模板参数 decltype(a)
表示指向函数的指针类型,同时也表示 class 类型。