#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/

10-16 04:44