现代C++模板元编程基础

元函数的基础介绍

C++的模板元编程是函数式编程,所以函数是一等公民。一切在编译期间执行的函数都可以称为元函数。元函数有structconstexpr两种定义方式,前者是一直使用的,后者是C++11以及以后版本的关键字。constexpr字面意思是常量表达式,因此表达式内部不允许出现运行期可以改变的量。

在元函数中,一切都是可计算的,也就是说,数值和数据类型都是可以计算的量。这和运行期的函数存在差异。

给出几个典型的例子,首先是struct类型的元函数:

#include 

template<typename T>
struct Fun_ {
    using type = T;
};

// 下面是模板的重载,注意格式
template<>
struct Fun_<int> {
    using type = unsigned int;
};

// 注意这种别名的方式
template<typename T>
using Fun = Fun_<T>::type;

int main() {
    Fun_<float>::type h = 1.0;
    Fun_<int>::type   h1 = 0;
    Fun<float>        h2 = 2.0;
    return 0;
}

上述函数完成了一个功能,用type表示传进来的数据类型,如果是int类型,则转换成unsgned int类型,利用模板重载来实现。同时也可以看出,模板元函数的参数是在尖括号<>内部传入的,这一点和运行期函数是不同的。

上述的代码完成的类型的计算,因为类型计算涉及到using,所以只能使用struct。如果涉及到数值的计算,给出下面一个例子,计算奇偶性。下面给出两种类型实现的对比:

#include 

template<size_t N>
struct IsOdd_ {
    constexpr static bool value = ((N % 2) == 1);
};

template<size_t N>
constexpr static bool IsOdd = ((N % 2) == 1);

int main() {
    // 尖括号就相当于实际的参数传入,只不过在编译期间完成计算 
    std::cout << IsOdd_<11>::value << std::endl;
    std::cout << IsOdd<11> << std::endl;

    return 0;
}

个人对于元函数的理解是:只要能在编译期间完成计算,而且不会产生副作用的表达式,都可以作为元函数

type_traits库

首先说明的是两个std::enable_ifstd::enable_if_t。给出参考地址:https://zh.cppreference.com/w/cpp/types/enable_if

这两个函数完成上个例子中的Fun_的类型转换的功能,一个可能的实现方式是:

template<bool B, typename T = void>
struct enable_if {};

template<typename T>
struct enable_if<true, T> {
    using type = T;
};

// C++14起
template<bool B, typename T = void>
using enable_if_t = typename enable_if<B, T>::type;

使用方式为:

#include 
#include 

int main() {
    std::enable_if<true, int>::type b = 2;
    std::enable_if_t<true, int> b1 = 2;

    std::cout << b << std::endl;
    std::cout << b1 << std::endl;

    return 0;
}

用于处理引用的库函数std::remove_referencestd::remove_reference_t函数,原文连接:https://zh.cppreference.com/w/cpp/types/remove_reference

可能的实现方式:

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

// C++14以及以后
template< class T >
using remove_reference_t = typename remove_reference<T>::type;

用于处理条件的库函数std::conditionalstd::conditional_t

可能的实现方式:

template<bool B, class T, class F>
struct conditional { typedef T type; };
 
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

// C++14以及以后
template< bool B, class T, class F >
using conditional_t = typename conditional<B,T,F>::type;

模板类型作为参数

嵌套使用typename关键字,同时注意typename的使用方式,用于不定类型的推导声明。

#include 
#include 

template<template<typename>class T1, typename T2>
struct Fun_ {
    using type = typename T1<T2>::type;
};

template<template<typename>class T1, typename T2>
using Fun = typename Fun_<T1, T2>::type;

int main() {
    Fun<std::remove_reference, int> s;

    return 0;
}

你可能感兴趣的:(C++笔记)