这个模板元程序中的int ***如何工作?

时间:2016-12-18 07:45:00

标签: c++ templates template-meta-programming

模板元编程如何在此工作(static const int value = 1 + StarCounter<\U>::value;)以打印3

#include <iostream>

template <typename T>
struct StarCounter
{
    static const int value = 0;
};

template <typename U>
struct StarCounter<U*>
{
    static const int value = 1 + StarCounter<U>::value;
};

int main()
{
    std::cout << StarCounter<int***>::value << std::endl;//How is it printing 3?
    return 0;
}

4 个答案:

答案 0 :(得分:18)

第一个模板创建一个结构,当您调用StarCounter<U>::value时,该结构将始终返回0。

对于使用指针的情况,第二个模板专门针对第一个模板。因此,当您使用StarCounter<U*>::value调用它时,将使用第二个模板,而不是第一个模板,它将返回StarCounter<U>::value + 1。请注意,它会在每个递归步骤中删除指针。

所以对StarCounter<int***>::value的调用将花费在:

StarCounter<int***>::value // second template is used due to pointer
1 + StarCounter<int**>::value // second template is used due to pointer
1 + 1 + StarCounter<int*>::value // second template is used due to pointer
1 + 1 + 1 + StarCounter<int>::value // no pointer here, so first template is used
1 + 1 + 1 + 0
3

答案 1 :(得分:11)

StarCounter<int>::value

等于0,因为它与模板的第一次实例化相匹配,其中value已明确定义。

StarCounter<int*>::value = 1 + StarCounter<int>::value

等于1,因为StarCounter<int*>StarCounter<U*>匹配。是的,StarCounter<T>也可以视为匹配,但StarCounter<U*>更具体,这就是为什么首选这一点的原因。

类似地,

StarCounter<int**>::value = 1 + StarCounter<int*>::value

等于2

StarCounter<int***>::value = 1 + StarCounter<int**>::value

等于3

答案 2 :(得分:1)

我发现在元编程方面考虑运行时的等价物会有所帮助。在模板元编程中,我们使用部分特化,如在运行时编程中,我们使用递归。主模板用作基本案例,专门化用作递归案例。

考虑以下递归版本来确定容器的大小:

def size(x):
   if empty(x):
       return 0
   else:
       return 1 + size(tail(x))

这相当于您提供的模板代码。主要模板StarCounter<T>是基本案例。空案。它的大小(value)为零。专业化StarCounter<U*>是递归案例。它的大小(value1加上尾部递归的大小(StarCounter<U>)。

在C ++ 17中,我们甚至可以更明确地使元编程版本等同于运行时递归版本(这仅作为示例提供,而不是应该编写此代码的方式):

template <class T>
struct StarCounter {
    static constexpr int calc_value() {
        if constexpr (!std::is_pointer<T>::value) {
            return 0;
        }
        else {
            return 1 + StarCounter<std::remove_pointer_t<T>>::value;
        }
    }

    static constexpr int value = calc_value();
};

答案 3 :(得分:0)

有一个模板StarCounter,其中更通用的格式是常量value等于0。因此,当您对大多数类型使用此模板并请求value时,您将得到0。

此模板还有一个接受指针的专用版本。 它的实现也有常量value,它等于1(因为我们有一个指针,这意味着我们至少有一个星)加上该指针指向的value类型的值。

如果有三颗星,我们有:

StarCounter<int***>::value = 1 + StarCounter<int**>::value (1) + StarCounter<int*>::value (1) + StarCounter<int>::value (0)