美文网首页
C++11 模板元编程 - 一切都是类型

C++11 模板元编程 - 一切都是类型

作者: MagicBowen | 来源:发表于2016-09-15 22:15 被阅读1171次

下面我们实现一个能够判断两个类型是否相等的元函数:

template<typename T, typename U>
struct IsEqual
{
    enum {Result = false};
};

template<typename T>
struct IsEqual<T, T>
{
    enum {Result = true};
};

上面的实现中使用了模式特化,当两个类型相等时,选择特化版本,否则选择非特化版本。

接下来我们实现一个在编译期判断两个整数是否相等的元函数:

template<int N, int M>
struct IsNumEqual
{
    enum {Result = false};
};

template<int N>
struct IsNumEqual<N, N>
{
    enum {Result = true};
};

我们看到,判断整数是否相等的元函数的实现和前面对类型进行判断的元函数的实现完全一样,唯独入参类型不同。由于元函数不支持函数重载,所以必须得为这两个元函数起不同的函数名称。

另外,我们之前一直用Result表示返回类型,现在又用它返回数值。这种返回型别上的差异,会让我们在函数组合的时候碰到不少问题。

如果我们能有一个方法,让所有的元函数的入参的型别和返回值型别都能一致化,那将对元函数的复用和组合带来极大的好处。

有一个办法可以让我们把数值也变成一个类型。

// “tlp/int/IntType.h”

template<int V>
struct IntType
{
    enum { Value = V };
    using Result = IntType<V>;
};

有了IntType,我们可以让每个整形数字都成为不同的类型,例如IntType<3>IntType<4>就是不同的类型。虽然可以使用IntType<3>::Value获得它的数值,但在模板元编程中我们更倾向直接使用这种对数值封装过后的类型,因为这样可以让模板元编程的计算对象统一成一种:只有类型

同理,对于bool值,也如此封装:

// “tlp/bool/BoolType.h”

template<bool V> struct BoolType;

template<>
struct BoolType<true>
{
    enum { Value = true };
    using Result = BoolType<true>;
};

template<>
struct BoolType<false>
{
    enum { Value = false };
    using Result = BoolType<false>;
};

using TrueType = BoolType<true>;
using FalseType = BoolType<false>;

用了该技术,后续所有元函数的入参和返回值都只面向类型,再没有数值。如此归一化后,将会从根本上避免由于元编程的操作对象不一致造成的写法上的重复,进一步让元函数的组合能力变得更强。

得益于上述统一,IsEqual只需要如下一份实现就够了:

// “tlp/bool/algo/IsEqual.h”

template<typename T, typename U>
struct IsEqual
{
    using Result = FalseType;
};

template<typename T>
struct IsEqual<T, T>
{
    using Result = TrueType;
};

前面我们实现过一个Print模板,用于在编译过程中打印常量的值。现在一切都是类型,我们对Print的实现进行修改,让其可以在编译期打印出类型结果的值。

// “tlp/test/details/Print.h”

template <typename T>
struct Print
{
    const int Value = 1 / (sizeof(T) - sizeof(T));
};

#define __print(...) Print<__VA_ARGS__> UNIQUE_NAME(tlp_print_)

现在Print的入参变为一个类型T,使用__print(T)会产生一个编译器的告警,在告警信息中输出T的具体类型。__print()在输出前会先对其参数进行求值。

// TestPrint.cpp

__print(IsEqual<IntType<5>, IntType<6>>::Result);
__print(IsEqual<TrueType, BoolType<true>>::Result);

上面的cpp文件在我的编译环境下输出的告警信息中包含如下内容,其中携带着对__print()的参数的求值结果。

TestPrint.cpp : in instantiation of default member initializer Print<BoolType<false> >::Value' required here
...
TestPrint.cpp : in instantiation of default member initializer Print<BoolType<true> >::Value' required here

可见IsEqual<IntType<5>, IntType<6>>::Result的值是BoolType<false>,而IsEqual<TrueType, BoolType<true>>::Result的值是BoolType<true>

得益于我们将元编程的计算统一到类型上,我们得到了一个统一的Print元函数。


一切都是函数

返回 C++11模板元编程 - 目录

相关文章

  • C++11 模板元编程 - 类型校验

    一般情况下一个系统可以发送和接收的消息是确定的。例如前面的例子中,visitor可以发送AccessReq消息,可...

  • C++11 模板元编程 - 类型萃取

    类型萃取(trait)的概念我们前面有介绍过。可以将trait看做是一种静态反射技术,通过trait我们可以自动提...

  • C++11 模板元编程 - 类型选择

    上面我们在send的函数实现中创建了一个msg,它的内存是在函数栈空间上临时申请的。一般系统间发送的消息可能会比较...

  • C++11 模板元编程 - 类型操纵

    本文最开始介绍模板元编程的时候说过,模板元编程是写C++框架离不开的技术。本例将通过介绍模板元编程在dates框架...

  • C++11 模板元编程 - 模板的类型参数

    下面是我们熟悉的类模板的例子:一个简单的容器栈,它可以支持不同的类型做元素。 它的用法如下: 对于模板元编程,我们...

  • C++11 模板元编程 - 模板的类型计算

    除了可以计算数值,编译期更具有价值的是类型计算。我们可以将编译期常量和类型都看做是编译期的可计算对象。 我们知道模...

  • C++11 模板元编程 - 一切都是类型

    下面我们实现一个能够判断两个类型是否相等的元函数: 上面的实现中使用了模式特化,当两个类型相等时,选择特化版本,否...

  • C++11 模板元编程 - 元编程

    从本节开始我们将模板元编程当做一门独立的函数式语言来讨论它的方方面面。 所谓元编程,就是指可以产生程序的程序。由于...

  • C++11 模板元编程 - 鸭子类型

    模板为C++提供了鸭子类型(Duck typing)的特性。所谓鸭子类型,指的是代码关注的不是对象的类型本身,而是...

  • C++11 模板元编程 - 模板的非类型参数

    前面的例子中,我们分别使用了类型和模板作为类模板的参数。除此之外,模板还支持非类型模板参数。 如下用数组实现Sta...

网友评论

      本文标题:C++11 模板元编程 - 一切都是类型

      本文链接:https://www.haomeiwen.com/subject/vpibettx.html