通过 lambda 部分特化 class 模板
Partially specialize class template by lambda
我有存储有关函数或成员函数信息的模板类型(如 return 类型、数字或参数等)。
template<class R, class... FuncParams>
struct SFuncInfo
{
using Signature = R(FuncParams...);
using Ret = R;
static constexpr size_t numParams = sizeof...(FuncParams);
};
// member
template<class T, class Ret, class... Params>
struct SFuncInfo<Ret(T::*)(Params...)> : SFuncInfo<Ret, Params...>
{
static constexpr bool isMemberFunction = true;
};
// function
template<class R, class... FuncParams>
struct SFuncInfo<R(FuncParams...)> : SFuncInfo<R, FuncParams...>
{
static constexpr bool isMemberFunction = false;
};
这是它的用法:
int func(const char* str) { return 1; }
struct MyType
{
bool memFunc(int val, float fl) { return true; }
};
int main()
{
static_assert(!SFuncInfo<decltype(func)>::isMemberFunction, "");
static_assert(std::is_same<SFuncInfo<decltype(func)>::Ret, int>::value, "");
static_assert(SFuncInfo<decltype(&MyType::memFunc)>::isMemberFunction, "");
static_assert(std::is_same<SFuncInfo<decltype(&MyType::memFunc)>::Ret, bool>::value, "");
}
此代码编译通过。但我也想用 lambda 处理案例。像这样:
auto lambda = [](int, bool) -> float { return 3.14f; };
static_assert(SFuncInfo<decltype(lambda)>::isMemberFunction, "");
static_assert(std::is_same<SFuncInfo<decltype(lambda)>::Ret, float>::value, "");
我尝试了不同的选择。下面列出了其中的一小部分。
template<class T>
struct SFuncInfo<T, decltype(T())>
{
static constexpr bool isMemberFunction = true;
};
template<class T>
struct SFuncInfo<T, decltype(&std::decay<decltype(std::declval<T>())>::type::operator())>
{
static constexpr bool isMemberFunction = true;
};
它没有解决任何这些专业化。
顺便说一句,下面的代码也可以编译:
auto lambda = [](int, bool) -> float { return 3.14f; };
using LambdaType = std::decay<decltype(std::declval<decltype(lambda)>())>::type;
using CallOperator = decltype(&LambdaType::operator());
static_assert(std::is_same<SFuncInfo<CallOperator>::Ret, float>::value, "");
static_assert(SFuncInfo<CallOperator>::isMemberFunction, "");
这里LIVE DEMO有人想玩
有人对此有好的解决方案吗?
添加这个单一的部分专业化对我有利:
template<class Lambda>
struct SFuncInfo<Lambda> : SFuncInfo<decltype(&Lambda::operator())> { };
解决方案是创建一个仅可用于可调用对象类型的重载,并从具有 operator()
类型的 SFuncInfo
继承。
template<typename T>
struct SFuncInfo<T, decltype(void(&T::operator()))> : SFuncInfo<decltype(&T::operator())> {};
// constraint ----------------^
然而,为了支持这一点,我将专业化和元数据分开 类,将它们分成 SFuncInfo
和 SFuncInfoBase
:
template<class R, class... FuncParams>
struct SFuncInfoBase
{
using Signature = R(FuncParams...);
using Ret = R;
static constexpr size_t numParams = sizeof...(FuncParams);
};
template<class T, typename = void>
struct SFuncInfo;
// member
template<class T, class Ret, class... Params>
struct SFuncInfo<Ret(T::*)(Params...)const> : SFuncInfo<Ret(T::*)(Params...)> {};
template<class T, class Ret, class... Params>
struct SFuncInfo<Ret(T::*)(Params...)> : SFuncInfoBase<Ret, Params...>
{
static constexpr bool isMemberFunction = true;
};
我有存储有关函数或成员函数信息的模板类型(如 return 类型、数字或参数等)。
template<class R, class... FuncParams>
struct SFuncInfo
{
using Signature = R(FuncParams...);
using Ret = R;
static constexpr size_t numParams = sizeof...(FuncParams);
};
// member
template<class T, class Ret, class... Params>
struct SFuncInfo<Ret(T::*)(Params...)> : SFuncInfo<Ret, Params...>
{
static constexpr bool isMemberFunction = true;
};
// function
template<class R, class... FuncParams>
struct SFuncInfo<R(FuncParams...)> : SFuncInfo<R, FuncParams...>
{
static constexpr bool isMemberFunction = false;
};
这是它的用法:
int func(const char* str) { return 1; }
struct MyType
{
bool memFunc(int val, float fl) { return true; }
};
int main()
{
static_assert(!SFuncInfo<decltype(func)>::isMemberFunction, "");
static_assert(std::is_same<SFuncInfo<decltype(func)>::Ret, int>::value, "");
static_assert(SFuncInfo<decltype(&MyType::memFunc)>::isMemberFunction, "");
static_assert(std::is_same<SFuncInfo<decltype(&MyType::memFunc)>::Ret, bool>::value, "");
}
此代码编译通过。但我也想用 lambda 处理案例。像这样:
auto lambda = [](int, bool) -> float { return 3.14f; };
static_assert(SFuncInfo<decltype(lambda)>::isMemberFunction, "");
static_assert(std::is_same<SFuncInfo<decltype(lambda)>::Ret, float>::value, "");
我尝试了不同的选择。下面列出了其中的一小部分。
template<class T>
struct SFuncInfo<T, decltype(T())>
{
static constexpr bool isMemberFunction = true;
};
template<class T>
struct SFuncInfo<T, decltype(&std::decay<decltype(std::declval<T>())>::type::operator())>
{
static constexpr bool isMemberFunction = true;
};
它没有解决任何这些专业化。
顺便说一句,下面的代码也可以编译:
auto lambda = [](int, bool) -> float { return 3.14f; };
using LambdaType = std::decay<decltype(std::declval<decltype(lambda)>())>::type;
using CallOperator = decltype(&LambdaType::operator());
static_assert(std::is_same<SFuncInfo<CallOperator>::Ret, float>::value, "");
static_assert(SFuncInfo<CallOperator>::isMemberFunction, "");
这里LIVE DEMO有人想玩
有人对此有好的解决方案吗?
添加这个单一的部分专业化对我有利:
template<class Lambda>
struct SFuncInfo<Lambda> : SFuncInfo<decltype(&Lambda::operator())> { };
解决方案是创建一个仅可用于可调用对象类型的重载,并从具有 operator()
类型的 SFuncInfo
继承。
template<typename T>
struct SFuncInfo<T, decltype(void(&T::operator()))> : SFuncInfo<decltype(&T::operator())> {};
// constraint ----------------^
然而,为了支持这一点,我将专业化和元数据分开 类,将它们分成 SFuncInfo
和 SFuncInfoBase
:
template<class R, class... FuncParams>
struct SFuncInfoBase
{
using Signature = R(FuncParams...);
using Ret = R;
static constexpr size_t numParams = sizeof...(FuncParams);
};
template<class T, typename = void>
struct SFuncInfo;
// member
template<class T, class Ret, class... Params>
struct SFuncInfo<Ret(T::*)(Params...)const> : SFuncInfo<Ret(T::*)(Params...)> {};
template<class T, class Ret, class... Params>
struct SFuncInfo<Ret(T::*)(Params...)> : SFuncInfoBase<Ret, Params...>
{
static constexpr bool isMemberFunction = true;
};