C++的模板元编程是函数式编程,所以函数是一等公民。一切在编译期间执行的函数都可以称为元函数。元函数有struct
和constexpr
两种定义方式,前者是一直使用的,后者是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;
}
个人对于元函数的理解是:只要能在编译期间完成计算,而且不会产生副作用的表达式,都可以作为元函数。
首先说明的是两个std::enable_if
和std::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_reference
和std::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::conditional
和std::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;
}