【问题标题】:Understand how to compute sum at compile time了解如何在编译时计算总和
【发布时间】:2013-09-11 15:42:20
【问题描述】:

我有这段代码,想了解一下:

template <unsigned...>
struct sum;

template<unsigned size>
struct sum<size>
{
    enum {value = size};
};

template<unsigned size, unsigned... sizes>
struct sum<size, sizes...>
{
    enum { value = size + sum<sizes...>::value }; 
};

int _tmain(int argc, _TCHAR* argv[])
{
    sum<1, 2>::value;
    return 0;
}

我不明白为什么必须存在未实现的总和(它需要无符号......就像最后一个结构特化,没有冲突吗?)以及如何使用模板部分中的相同参数来特化总和(e.g. sum&lt;size, sizes...&gt;template &lt;unsigned size, sizes...&gt; 相同。 为什么波纹管不起作用?

template<unsigned size>
struct sum
{
    enum {value = size};
};

template<unsigned size, unsigned... sizes>
struct sum
{
    enum { value = size + sum<sizes...>::value; }; 
};

【问题讨论】:

    标签: c++ c++11 variadic-templates template-specialization template-meta-programming


    【解决方案1】:

    请注意,语法有点不同。声明主模板时:

    template <unsigned...>
    struct sum;
    

    sum 后面没有给出模板参数。这是因为您正在创建一个全新的模板,并说它接受任意数量的无符号整数作为参数。

    当你这样做时:

    template<unsigned size, unsigned... sizes>
    struct sum<size, sizes...>
    {
        enum { value = size + sum<sizes...>::value }; 
    };
    

    您正在专门化您之前声明的模板。您是说,如果您的参数由一个无符号值后跟任意数量的其他无符号值组成,请使用此定义。这与主模板不完全相同。主模板包括具有零参数的可能性。

    当您尝试这样做时:

    template<unsigned size>
    struct sum
    {
        enum { value = size };
    };
    
    template<unsigned size, unsigned... sizes>
    struct sum // OOPS! A template called `sum` has already been declared!
    {
        enum { value = size + sum<sizes...>::value }; 
    };
    

    您正在尝试使用相同名称创建两个不同的类模板,这是不允许的。

    请注意,这与函数模板的工作方式有些不同。使用函数模板,您可以进行重载,因此拥有多个同名的函数模板就可以了。但是,对于函数模板,您不能进行部分特化,因为这会产生很多歧义。

    您可能认为主模板和特化之间存在歧义,但更特化的特化总是优先于不太特化的特化,并且主模板总是被认为是最不特化的。如果这不是真的,那么部分专业化将根本不起作用。

    【讨论】:

    • 是的,我现在明白了,关于命名部分。但是为什么第一个未实现的总和不会与最后一个相撞(模棱两可)?当用户调用 sum 时,它应该匹配未实现的和最后的特化
    • @Gmt:没错,但专业优先。我已经在我的回答中添加了一个注释。
    【解决方案2】:

    第一个声明:

    template<unsigned int... Ns>
    struct sum;
    

    是前向声明:它将模板声明为具有可变数量的unsigned int 参数的模板。

    第一个特化是元函数的基本情况,它适用于可变参数包只有一个参数的情况:

    template<unsigned size>
    struct sum<size>
    {
        enum {value = size};
    };
    

    第二个特化是递归情况:它适用于可变参数包至少有一个参数的情况:

    template<unsigned size, unsigned... sizes>
    struct sum<size, sizes...>
    {
        enum { value = size + sum<sizes...>::value }; 
    };
    

    我建议您在编写/学习模板元编程之前了解更多关于 C++ 模板机制(如实例化、模板专业化等)的信息。

    【讨论】:

    • 一个前向声明只是一个声明。没什么特别的,为什么要强调它呢?如果有的话,强调它是一个主要的类模板声明
    • @Nawaz 我试图强调前向声明可以被视为元函数的声明,并且特化是递归元函数的情况。跨度>
    【解决方案3】:

    有了c++20的新特性,你可以这样解决问题:

    • 用许多参数初始化struct

      template<int ...args> 
      
    • 您的结果将是const auto

      static const auto value = (0 + ... + args);
      
    • auto关键字在c++17中定义,可以推断函数的返回类型。

    代码:


    #include <iostream>
    
    template<int ...args>
    struct sum
    {
        static const auto value = (0 + ... + args);
    };
    
    int main(int argc, char *argv[])
    { 
        const auto res = sum<10, 20, 40, -5>();
        std::cout << "Result ";
        std::cout << res.value;
        std::cout << std::endl;
        return 0;
    }
    

    结果:

    Result 65
    

    【讨论】:

      猜你喜欢
      • 2012-10-09
      • 2020-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 2011-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多