模板化类构造函数中定义的 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 实例化的某个地方看到了问题,但不明白在哪里。