接受所有成员函数指针(包括CV-qualified和ref-qualified)的模板



我想写一个模板,它接受一个指向成员函数的指针(可能是cv限定的和/或ref限定的),同时也匹配所有相关类型(返回值的类型,类类型和参数的类型)。

简单的版本可以像这样:

template <typename ReturnValue, typename Class, typename... Arguments>
void foo(ReturnValue(Class::* function_ptr)(Arguments...))
{
// do something with |function_ptr|
}

对于非cv限定的非ref限定的成员函数指针来说,这工作得很好,但是不能与指向cv限定和/或ref限定的成员函数的指针匹配。

是否有一种很好的方法将其保存在单个模板中,并通过某种方式很好地推导限定符来处理所有情况?


我可以降级到一个简单的模板,接受一切(可能有一些SFINAE围绕std::is_member_function_pointer)。但是我仍然需要在某个地方提取类型(return, class和arguments),所以这实际上不会节省我的任何工作。

如何将成员函数指针传递给foo,并使用helper trait检索类,返回和参数的类型!

提供如下特征:

template<typename Class> struct class_traits final {};
template<typename ReType, typename Class, typename... Args>
struct class_traits<ReType(Class::*)(Args...)> final
{
using class_type = Class;
using ret_type = ReType;
};    
// traits helpers
template<typename MemFunctionPtr> using  class_type = typename class_traits<MemFunctionPtr>::class_type;
template<typename MemFunctionPtr> using  ret_type = typename class_traits<MemFunctionPtr>::ret_type;

现在在foo

#include <functional> // std::invoke
template <typename MemFuncType, typename... Args>
void foo(MemFuncType&& func, Args&&... args) 
{
// class type can be retrieved!
class_type<MemFuncType> obj{};
// types other than void!!
ret_type<MemFuncType> res = std::invoke(func, obj, std::forward<Args>(args)...); 
// do something with |function_ptr|
}

现在是故事的主要部分。以上将只解析非const、非volatile和非noexcept等版本的成员函数指针。你要的东西不见了!

对于其余部分,我们需要提供不同的特征。受到这篇文章的启发,我们可以通过宏来实现,它将为我们复制这些特征的样板:

template<typename Class> struct class_traits final {};
#define CREATE_CLASS_TRAITS(...) 
template<typename ReType, typename Class, typename... Args> 
struct class_traits<ReType(Class::*)(Args...)__VA_ARGS__> final  
{ 
using class_type = Class; 
using ret_type = ReType; 
}
CREATE_CLASS_TRAITS();
CREATE_CLASS_TRAITS(const);
CREATE_CLASS_TRAITS(volatile);
CREATE_CLASS_TRAITS(const volatile);
CREATE_CLASS_TRAITS(&);
CREATE_CLASS_TRAITS(const&);
CREATE_CLASS_TRAITS(volatile&);
CREATE_CLASS_TRAITS(const volatile&);
CREATE_CLASS_TRAITS(&&);
CREATE_CLASS_TRAITS(const&&);
CREATE_CLASS_TRAITS(volatile&&);
CREATE_CLASS_TRAITS(const volatile&&);
CREATE_CLASS_TRAITS(noexcept);
CREATE_CLASS_TRAITS(const noexcept);
CREATE_CLASS_TRAITS(volatile noexcept);
CREATE_CLASS_TRAITS(const volatile noexcept);
CREATE_CLASS_TRAITS(&noexcept);
CREATE_CLASS_TRAITS(const& noexcept);
CREATE_CLASS_TRAITS(volatile& noexcept);
CREATE_CLASS_TRAITS(const volatile& noexcept);
CREATE_CLASS_TRAITS(&& noexcept);
CREATE_CLASS_TRAITS(const&& noexcept);
CREATE_CLASS_TRAITS(volatile&& noexcept);
CREATE_CLASS_TRAITS(const volatile&& noexcept);
#undef CREATE_CLASS_TRAITS
// traits helpers
template<typename MemFunctionPtr> using  class_type = typename class_traits<MemFunctionPtr>::class_type;
template<typename MemFunctionPtr> using  ret_type = typename class_traits<MemFunctionPtr>::ret_type;

现在可以:

template <typename MemFuncType, typename... Args>
void foo(MemFuncType&& func, Args&&... args) 
{
class_type<MemFuncType> obj{};
using Type = decltype(std::invoke(func, obj, std::forward<Args>(args)...));
static_assert(std::is_same_v<ret_type<MemFuncType>, Type>, "are not same");
std::invoke(func, obj, std::forward<Args>(args)...);
// do something with |function_ptr|
}
class MyClass
{
public:
void func() { std::cout << "MyClass::void func()n"; }
void func1() const { std::cout << "MyClass::void func1() constn"; }
void func2() const noexcept{ std::cout << "MyClass::void func2() const noexceptn"; }
int func3() const { std::cout << "MyClass::func3() constn";  return {}; }
int func4(int a, double b) const { std::cout << "MyClass::func3() const"<< a << " " << b << "n";  return {}; }
};
int main()
{
foo(&MyClass::func);
foo(&MyClass::func1);
foo(&MyClass::func2);
foo(&MyClass::func3);
foo(&MyClass::func4, 1, 2.);
return 0;
}

(参见Live Demo Online)

相关内容

  • 没有找到相关文章

最新更新