How to capture a type of return value of a functio

2019-07-20 05:58发布

Given this code:

template <class Func> class ScopeGuard
{
public:
    /** @param func function object to be executed in dtor
    */
    explicit ScopeGuard( Func && func ) : m_func( std::move(func) ) {}

    ~ScopeGuard()
    {
        if (m_bDismissed)
            return;
        m_func();
    }

    /** Dismisses the scope guard, i.e. the function won't
        be executed.
    */
    void dismiss() { m_bDismissed = true; }

private:
    // noncopyable until we have good reasons...
    ScopeGuard(const ScopeGuard&) = delete;
    ScopeGuard& operator=(const ScopeGuard&) = delete;

    Func m_func;
    bool m_bDismissed = false;
};

// Get functor for cleanup to use in FlagRestorationGuard
auto GetFlagRestorationGuard(bool& i_flagRef)
{
    return [&i_flagRef, resetVal = i_flagRef] { i_flagRef = resetVal; };
}

class FlagRestorationGuard : public ScopeGuard<decltype(GetFlagRestorationGuard(*(new bool)))>
{
public:
    FlagRestorationGuard( bool& i_flagRef, bool i_temporaryValue )
        : ScopeGuard(GetFlagRestorationGuard(i_flagRef))
    {
        i_flagRef = i_temporaryValue;
    }
};

I get the following error building with Apple Clang for GetFlagRestorationGuard(*(new bool)):

error: expression with side effects has no effect in an unevaluated context [-Werror,-Wunevaluated-expression]

Note that this code builds and works fine with MSVC 2017. Of course, it's possible to re-write it all to use a struct with operator()() instead of lambda and a function returning it, but I wonder if there is a nice way to use lambda like this?

Reference for the actual code:

Reference to build failure:

2条回答
祖国的老花朵
2楼-- · 2019-07-20 06:52

Use std::declval with an lvalue referrence to bool:

class FlagRestorationGuard :
    public ScopeGuard<decltype(GetFlagRestorationGuard(std::declval<bool&>()))>
{
    ...
};
查看更多
老娘就宠你
3楼-- · 2019-07-20 06:58

That's a warning you're seeing; not an error. It's warning you that the side-effect of new bool (allocating memory) will not happen because it's in an unevaluated context.

To get rid of the warning, instead of using *(new bool) as the placeholder argument in your decltype expression, use std::declval<bool&>.

查看更多
登录 后发表回答