【问题标题】:C++ template: cannot match the last template in variadic class templateC++ 模板:无法匹配可变参数类模板中的最后一个模板
【发布时间】:2018-11-16 15:00:26
【问题描述】:

我正在学习 C++11 可变参数模板并创建了一个模板结构来计算给定列表的最大数量并尝试:

#include <iostream>
#include <type_traits>

template <int a, int b, int... cs>
struct max: std::integral_constant<int, (a>b? max<a, cs...>::value: max<b, cs...>::value)> {};
template <int a, int b>
struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value: max<b>::value)> {};
template <int a>
struct max<a>: std::integral_constant<int, a> {};

int main() {
  std::cout << max<2,1,5,7>::value << std::endl;
  return 0;
}

但是 g++ 抱怨:

test.cc:7:58: error: wrong number of template arguments (1, should be at least 2)
 struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value : max<b>::value)> {};

test.cc:9:13: error: wrong number of template arguments (1, should be at least 2)
 struct max<a>: std::integral_constant<int, a> {};

我可以通过在前面添加一个简单的声明来让它运行:

template <int...>
struct max;

并将上面的第一个模板更改为:

template <int a, int b, int... cs>
struct max<a, b, cs...>: ...

我提到了cppreference:https://en.cppreference.com/w/cpp/language/partial_specialization#Partial_ordering 但我找不到任何有用的解释。

问题可能来自最后一个模板 (max&lt;a&gt;),它只有一个模板参数,不是主参数的专用版本。

所以我的问题是:

为什么max&lt;a&gt;无法匹配?是否有任何规则或标准处理这个问题?

================================================ ===================

好的,我找到了 C++ 标准(文档编号 N4659):

[ 注意:类模板的部分特化由 查找主要类模板并然后考虑所有部分 该模板的专业化。如果使用声明命名一个类 模板,部分专业化之后引入 using-declaration 是有效可见的,因为主模板 可见(17.5.5)。 ——尾注]

所以我认为任何不从基本/主要模板特化的部分特化模板都被认为是错误的,即使有时我们可以从正常的表达形式生成一些非特化形式。

【问题讨论】:

    标签: c++ c++11 templates variadic partial-ordering


    【解决方案1】:

    当您将类模板定义为:

    template <int a, int b, int... cs> struct max { ... };
    

    以下是有效的特化。

    template <int a, int b> struct max<a, b> { ... };
    

    但是,以下不是。

    template <int a> struct max<a> { ... };
    

    因为基类模板至少需要两个模板参数。

    【讨论】:

    • 那么标准是否要求以下部分规范模板必须是主要模板的专用版本?
    • @bigtit,我没听懂你的意思。请详细说明。
    • 你说 since the base class template requires at least two template parameters. 所以我假设 C++ 标准强制在基础模板之后的所有模板成为它的专用版本,因为在这种情况下 max&lt;a&gt; 不是更专业的版本基本模板?
    【解决方案2】:

    不是答案,但为什么不简单...

    template <int a, int... bs>
    struct max : std::integral_constant<int,
       (a > max<bs...>::value ? a : max<bs...>::value)> {};
    
    template <int a>
    struct max<a> : std::integral_constant<int, a> {};
    

    ...?

    【讨论】:

    • 你为什么不把它作为一个答案?它并没有从字面上回答这个问题,但这就是 OP 实际上所追求的,我猜
    • @user463035818 我不确定这一点,因为 OP 要求提供规则。他甚至知道如何通过添加另一个版本的主模板来使他的解决方案发挥作用。
    • 哦,你是对的。我误读了这个问题,已经想知道为什么顶级答案没有提到如何解决它;)
    【解决方案3】:

    您收到该错误的原因是模板的每次调用都必须首先匹配基本模板,然后才开始专门化。

    你的基本模板应该匹配任意数量的参数,并且没有实现(因为max&lt;&gt;::value 没有意义),并且只有一个可变参数,你的所有其他类都是专门的。

    #include <iostream>
    #include <type_traits>
    
    template<int... cs>
    struct max;
    
    template <int a, int b, int... cs>
    struct max<a, b, cs...>: std::integral_constant<int, (a>b? max<a, cs...>::value: max<b, cs...>::value)> {};
    template <int a, int b>
    struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value: max<b>::value)> {};
    template <int a>
    struct max<a>: std::integral_constant<int, a> {};
    
    int main() {
      std::cout << max<2,1,5,7>::value << std::endl;
      return 0;
    }
    

    【讨论】:

    • 实际上,我尝试了其他具有实现的主要模板的著作,它们运行良好。所以我假设你的意思是“应该”是一个约定?
    • @bigint,哦,是的,主模板可以有一个实现。只是在您的情况下,max&lt;&gt;::value 毫无意义,因此您应该将其保留为未定义。我已经修改了答案以澄清。
    • @Frank 有人会说max&lt;&gt;::value 应该是std::numeric_limits&lt;int&gt;::min()。否则,基本模板应至少需要一个模板参数。
    猜你喜欢
    • 2023-04-02
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多