了解功能特征模板的工作原理。特别是,指向成员函数的指针是怎么处理的

Understanding how the function traits template works. In particular, what is the deal with the pointer to member function

我正在尝试了解 this code and I have found some more SO content 这个话题。

紧凑形式:

#include <tuple>
namespace sqlite {
    namespace utility {
        template<typename> struct function_traits;

        template <typename Function>
        struct function_traits : public function_traits<
            decltype(&Function::operator())
        > {  };

        template <
            typename    ClassType,
            typename    ReturnType,
            typename... Arguments
        >
        struct function_traits<
            ReturnType(ClassType::*)(Arguments...) const
        > {
            typedef ReturnType result_type;

            template <std::size_t Index>
            using argument = typename std::tuple_element<
                Index,
                std::tuple<Arguments...>
            >::type;

            static const std::size_t arity = sizeof...(Arguments);

        };
    }
}

这让我了解了该语言的成员函数指针特性,此时我很清楚如何使用函数特征 (很简单,我不仅可以提取 return 类型,还可以提取参数的参数甚至类型),但我一直无法理解 为什么 这有效,或者确实为什么它甚至可以工作...

我确实意识到包括 ClassType::* 的部分是为了绑定到 decltype(&Function::operator())。我正在学习这个构造(指向成员函数的指针),但真的很难理解它存在的重要性。

ReturnType(ClassType::*)(Arguments...) const 是一个模板类型名,在本例中它是匹配一个指向成员函数的指针,它被巧妙地构造成绑定到 operator()成员函数,允许模式匹配为我们提取相关类型,即 args 和 return 类型。 ClassType 可能会被识别为与 Function 模板参数相同的东西。

我也很困惑为什么需要一个看起来很有趣的模板化 using 语句来查找参数类型值。然后我意识到 Arguments... 是一个可变参数模板类型构造,必须使用编译时功能对其进行元组化,并且整个业务与 "real" 元组无关。当我查找 tuple_element 时,它确实是作为一种在编译时操作类型的工具。

我不确定这个答案的其余部分

我确实想知道为什么使用指向成员函数的指针。我想原因可能是常规函数指针或某些此类构造实际上不能用于匹配仿函数的 operator () 成员,因为成员函数需要对象的实例才能变得可调用。 This answer 进一步阐明了这个主题。我想我现在大概明白了。

让我们一点一点地分解所有内容。

template<typename> struct function_traits;

这是主要的模板声明,使用单个模板参数声明模板class。

template <typename Function>
struct function_traits : public function_traits<
    decltype(&Function::operator())
> {  };

这本质上是一个转发特征,允许仿函数(具有 operator() 的对象)与此特征一起使用 class。它是从 operator() 的特征继承的主模板的定义。当后面定义的专业化不匹配时,将选择此版本。

template <
    typename    ClassType,
    typename    ReturnType,
    typename... Arguments
>
struct function_traits<
    ReturnType(ClassType::*)(Arguments...) const
>

这开始为指向成员函数的指针定义 function_traits 的偏特化。当您将成员函数指针类型作为模板参数传递给 function_traits 时,将选择此特化。 return 类型、class 类型和参数类型将被推导为模板参数。

    typedef ReturnType result_type;

这是一个简单的 typedef,它将推导的 ReturnType 模板参数别名为 result_type

    template <std::size_t Index>
    using argument = typename std::tuple_element<
        Index,
        std::tuple<Arguments...>
    >::type;

这就是所谓的别名模板。当您提供 function_traits<myFunc>::template argument<2> 之类的索引时,它会折叠成 typename std::tuple_element<2, std::tuple<Arguments...>>::type。这样做的目的是提取索引 Index 处的参数类型。作者没有写出所有模板元编程代码来手动执行此操作,而是选择使用 std::tuple 中的现有代码。 std::tuple_element 提取元组的第 n 个元素的类型。

   static const std::size_t arity = sizeof...(Arguments);

sizeof...用于获取可变模板参数包的大小,所以这一行存储了静态整数成员arity.

中函数的参数个数