0

模板化类构造函数中定义的 Lambda 在 GCC 5.5 上编译和工作,但在 Solaris Studio(以前的 SunPRO)12.6 上出现错误。

        m_method_ptr = [](void* object_ptr, func_ptr_type, ARGS... args) -> R
        {
            return static_cast<unref_type*>(object_ptr)->operator()(args...);
        };

有错误

"fixed_function.hpp", line 52: Error: Cannot use tp::FixedFunction<std::string (), 128>::FixedFunction<main::{lambda at test.cc,21:40}>::{lambda at fixed_function.hpp,52:24} to initialize std::string (*)(void*,std::string (*)()).
"test.cc", line 21:     Where: While instantiating "void tp::FixedFunction<std::string (), 128>::FixedFunction<main::{lambda at test.cc,21:40}>(main::{lambda at test.cc,21:40}&&)".
"test.cc", line 21:     Where: Instantiated from non-template code.
1 Error(s) detected.

我完全不知道为什么。当然,我几年前就找到了解决方法,但我不喜欢它并试图解决它。

完整的模块代码在这里(不是那么大)。

我试过谷歌它,但没有发现任何有用的东西。当我注释掉这个 lambda 时,错误消失了。所以,它就在这里。

可能是,有人遇到过这种情况或可以指出我正确的方式吗?

这是最小的可重现示例。请注意 - 它在 GCC/CLang 上编译和运行,而不是在 CC (SunStudio) 上。

#include <type_traits>
#include <cstring>
#include <stdexcept>
#include <utility>

namespace tp
{

/**
 * @brief The FixedFunction<R(ARGS...), STORAGE_SIZE> class implements
 * functional object.
 * This function is analog of 'std::function' with limited capabilities:
 *  - It supports only move semantics.
 *  - The size of functional objects is limited to storage size.
 * Due to limitations above it is much faster on creation and copying than
 * std::function.
 */
template <typename SIGNATURE, std::size_t STORAGE_SIZE = 128>
class FixedFunction;

template <typename R, typename... ARGS, std::size_t STORAGE_SIZE>
class FixedFunction<R(ARGS...), STORAGE_SIZE>
{

    typedef R (*func_ptr_type)(ARGS...);

public:
    FixedFunction()
        : m_function_ptr(nullptr), m_method_ptr(nullptr),
          m_alloc_ptr(nullptr)
    {
    }

    /**
     * @brief FixedFunction Constructor from functional object.
     * @param object Functor object will be stored in the internal storage
     * using move constructor. Unmovable objects are prohibited explicitly.
     */
    template <typename FUNC>
    FixedFunction(FUNC&& object)
        : FixedFunction()
    {
        typedef typename std::remove_reference<FUNC>::type unref_type;

        static_assert(sizeof(unref_type) < STORAGE_SIZE,
            "functional object doesn't fit into internal storage");
        static_assert(std::is_move_constructible<unref_type>::value,
            "Should be of movable type");

        m_method_ptr = [](void* object_ptr, func_ptr_type, ARGS... args) -> R   // <--- Problem here
        {
            return static_cast<unref_type*>(object_ptr)->operator()(args...);
        };

        m_alloc_ptr = [](void* storage_ptr, void* object_ptr)
        {
            if (object_ptr)
            {
                unref_type* x_object = static_cast<unref_type*>(object_ptr);
                new(storage_ptr) unref_type(std::move(*x_object));
            }
            else
            {
                static_cast<unref_type*>(storage_ptr)->~unref_type();
            }
        };

        m_alloc_ptr(&m_storage, &object);
    }

    /**
     * @brief FixedFunction Constructor from free function or static member.
     */
    template <typename RET, typename... PARAMS>
    FixedFunction(RET (*func_ptr)(PARAMS...))
        : FixedFunction()
    {
        m_function_ptr = func_ptr;
        m_method_ptr = [](void*, func_ptr_type f_ptr, ARGS... args) -> R
        {
            return static_cast<RET (*)(PARAMS...)>(f_ptr)(args...);
        };
    }

    FixedFunction(FixedFunction&& o) : FixedFunction()
    {
        moveFromOther(o);
    }

    FixedFunction& operator=(FixedFunction&& o)
    {
        moveFromOther(o);
        return *this;
    }

    ~FixedFunction()
    {
        if (m_alloc_ptr) m_alloc_ptr(&m_storage, nullptr);
    }

    /**
     * @brief operator () Execute stored functional object.
     * @throws std::runtime_error if no functional object is stored.
     */
    R operator()(ARGS... args)
    {
        if (!m_method_ptr) throw std::runtime_error("call of empty functor");
        return m_method_ptr(&m_storage, m_function_ptr, args...);
    }

private:
    FixedFunction& operator=(const FixedFunction&) = delete;
    FixedFunction(const FixedFunction&) = delete;

    union
    {
        typename std::aligned_storage<STORAGE_SIZE, sizeof(std::size_t)>::type
            m_storage;
        func_ptr_type m_function_ptr;
    };

    typedef R (*method_type)(
        void* object_ptr, func_ptr_type free_func_ptr, ARGS... args);
    method_type m_method_ptr;

    typedef void (*alloc_type)(void* storage_ptr, void* object_ptr);
    alloc_type m_alloc_ptr;

    void moveFromOther(FixedFunction& o)
    {
        if (this == &o) return;

        if (m_alloc_ptr)
        {
            m_alloc_ptr(&m_storage, nullptr);
            m_alloc_ptr = nullptr;
        }
        else
        {
            m_function_ptr = nullptr;
        }

        m_method_ptr = o.m_method_ptr;
        o.m_method_ptr = nullptr;

        if (o.m_alloc_ptr)
        {
            m_alloc_ptr = o.m_alloc_ptr;
            m_alloc_ptr(&m_storage, &o.m_storage);
        }
        else
        {
            m_function_ptr = o.m_function_ptr;
        }
    }
};

}

// 

int main(int argc, char **argv) {
    const std::string s1 = "s1";
    tp::FixedFunction<std::string()> f([&s1]() { return s1; });
    auto f1 = std::move(f);
}

对任何想法都会很感激。我在 ARGS 实例化的某个地方看到了问题,但不明白在哪里。

4

0 回答 0