C++ 通过lambda部分专门化类模板

C++ 通过lambda部分专门化类模板,c++,templates,lambda,c++14,variadic-templates,C++,Templates,Lambda,C++14,Variadic Templates,我有存储函数或成员函数信息的模板类型(如返回类型、编号或参数等) 模板 结构sfuninfo { 使用Signature=R(FuncParams…); 使用Ret=R; 静态constexpr size\u t numParams=sizeof…(FuncParams); }; //成员 模板 结构sfuninfo:sfuninfo { 静态constexpr bool isMemberFunction=true; }; //作用 模板 结构sfuninfo:sfuninfo { 静态cons

我有存储函数或成员函数信息的模板类型(如返回类型、编号或参数等)

模板
结构sfuninfo
{
使用Signature=R(FuncParams…);
使用Ret=R;
静态constexpr size\u t numParams=sizeof…(FuncParams);
};
//成员
模板
结构sfuninfo:sfuninfo
{
静态constexpr bool isMemberFunction=true;
};
//作用
模板
结构sfuninfo:sfuninfo
{
静态constexpr bool isMemberFunction=false;
};
这就是它的使用方法:

int func(const char*str){return 1;}
结构MyType
{
boolmemfunc(int-val,float-fl){返回真;}
};
int main()
{
静态断言(!sfuninfo::isMemberFunction,“”);
静态断言(std::is_same::value,“”);
静态断言(sfuninfo::isMemberFunction,“”);
静态断言(std::is_same::value,“”);
}
这段代码可以编译。但我还想处理lambdas的案子。大概是这样的:

autolambda=[](int,bool)->float{return 3.14f;};
静态断言(sfuninfo::isMemberFunction,“”);
静态断言(std::is_same::value,“”);
我尝试了不同的选择。下面列出了其中的几个例子

模板
结构sfuninfo
{
静态constexpr bool isMemberFunction=true;
};
模板
结构sfuninfo
{
静态constexpr bool isMemberFunction=true;
};
它不能解决这些专门化问题

顺便说一下,下面的代码也可以编译:

autolambda=[](int,bool)->float{return 3.14f;};
使用LambdaType=std::decay::type;
使用CallOperator=decltype(&LambdaType::operator());
静态断言(std::is_same::value,“”);
静态断言(sfuninfo::isMemberFunction,“”);
这是一个想玩的人


有人对此有好的解决方案吗?

添加此单一部分专门化对我来说很有效:

template<class Lambda>
struct SFuncInfo<Lambda> : SFuncInfo<decltype(&Lambda::operator())> { };
模板
结构sfuninfo:sfuninfo{};

解决方案是使重载仅对可调用对象类型可用,并使用
操作符()从
sfuninfo
继承

template<typename T>
struct SFuncInfo<T, decltype(void(&T::operator()))> : SFuncInfo<decltype(&T::operator())> {};
//     constraint ----------------^

不是
std::decay::type
只是
std::decay\u t
?您当前的代码为0参数自由函数中断,该函数返回0参数成员函数指针(对于自由函数,它只是勉强避免了这个问题,因为您只能返回函数指针[对于自由函数,您不专门使用函数指针],而不是功能)。这是因为您将专门化中的
R
重新用作输入模板参数,因此如果继承的
sfuninfo
参数为空
Params
,并且可以再次专门化
Ret
,则您将失败。请不要像那样重新调整模板参数的用途@麦克斯兰霍夫,谢谢你的评论。非常有用,但是你能详细说明一下重新调整用途吗?也许是一个例子?@Peregrin第一个模板参数被称为
R
,如
ReturnType
。但是专门化的语义是“
R
是要检查的函数(指针)类型”。它恰好在99%的情况下工作,但是
SFuncInfo
在语义上解析为“返回
int*
且不带参数的函数返回的类型”,而
SFuncInfo
解析为“用于推断返回
int*
且不带参数的函数信息的类型”是有问题的,因为在后一种情况下,
R
不是返回值,而是输入类型。“我希望这是有道理的。”麦克斯兰霍夫,我想我明白了。但这个问题似乎是由下面GuillaumeRacicot提出的解决方案解决的。你不同意吗?我完全同意元数据应该与专门化分开。否则,要证明这不能以其他方式进行递归或行为异常(例如,如果函数返回其他函数指针),这绝非易事。这是一个非常优雅的解决方案,但事实证明,它不适用于没有参数的成员函数。我更新了live demo的链接以添加此案例。
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;
};