首页 > 解决方案 > 使用声明和实例化中的默认模板参数

问题描述

编辑:
显然,GCC 允许实例化没有参数列表的类模板(当参数默认时),这是不符合的(符合 Clang 的)。
我猜测需要括号的原因(即使参数列表为空)是为了明确表明它是模板实例化,而不是实际类型。
所以我将我最初的问题转向类模板和函数模板案例之间的差异:为什么在第二个片段中,它允许调用不带括号的 a ,而不是在第一个片段中实例化 A ?为什么b不允许?


原文:
一个只有默认参数的类模板可以在没有任何参数列表的情况下实例化(见下面的A)。
但是,如果该类模板的别名通过 using 声明定义为具有相同默认参数的模板(参见下面的 B),则其实例化需要一个参数列表(可能为空)。
类似地,将类模板的别名定义为实际类型(参见下面的 C)需要一个参数列表(同样,可能为空)。
这背后有什么原因吗?

template<int i = 1>
struct A {
    operator int() { return i; }
};

template<int i = 2>
using B = A<i>;

// using C = A;    <-- error: missing template arguments after 'A'
using C = A<>;

int main() {
    A a; // Edit: Actually should require brackets: A<> a;
    // B b;    <-- error: missing template arguments before 'b'
    B<> b;
    C c;
}

住在科利鲁

我曾尝试使用函数模板而不是类模板构建类似的场景,最后一种情况(C)略有不同:如果在定义中指定了返回类型,则不需要参数列表a。我想我明白为什么,但我欢迎一些见解。否则,这两种情况都类似于类模板的情况。

template<int i = 1>
auto a() { return i; }
// auto a() -> int { return i; }
// if the return type is specified, c can be defined as commented below

template<int i = 2>
auto b = a<i>;

// auto c = a;    <-- error: unable to deduce 'auto' from 'a'
auto c = a<>;

int main() {
    a();
    // b();    <-- error: missing template arguments before '(' token
    b<>();
    c();
}

住在科利鲁

此外,现代 C++ 标准(C++11 到 C++20)之间是否存在显着差异?我最感兴趣的是 C++17 案例,但我很想知道这些事情是否已经改变,或者将会改变。
据我所知,在 C++14 中,类模板实例化无论如何都需要参数列表,而函数模板调用则不需要。而且我还没有发现 C++17 和 C++2a 与 GCC 之间的区别。

标签: c++templateslanguage-lawyerc++17

解决方案


模板参数 [temp.arg]/4 (§12.3/4)

当使用模板参数包或默认模板参数时,模板参数列表可以为空。在这种情况下,空<>括号仍应用作template-argument-list

§17.3/4 中的 C++17 和 §14.3/4 中的 C++14 和 C++11 的措辞相同。

显式模板参数规范 [temp.arg.explicit] (§12.9.1/3)

如果所有的模板参数都可以推导出来,那么它们都可以被省略;在这种情况下,空模板参数列表<>本身也可以省略。

§17.8.1/3 中的 C++17 和 §14.8.1/3 中的 C++14 和 C++11 的措辞相同。


您的

template<int i = 2>
auto b = a<i>;

是一个变量模板,不会发生任何参数推导。


推荐阅读