查看原文
其他

新简化!typename 在 C++20 不再必要

CPP开发者 2023-07-27

The following article is from CPP编程客 Author 里缪

根据提案P0634-Down with typename,C++20之后typename在有些地方不再必要。

原文主要内容如下:

If X::Y — where T is a template parameter — is to denote a type, it must be preceded by the keyword typename; otherwise, it is assumed to denote a name producing an expression. There are currently two notable exceptions to this rule: base-specifiers and mem-initializer-ids. For example:


template<class T>
struct D: T::B { // No typename required here.
};


Clearly, no typename is needed for this base-specifier because nothing but a type is possible in that context. 

简言之,以前若需要使用模板中的嵌套类型,必须在前面加上typename以表示这是一个类型。
而编译器供应商很快意识到在许多语境下其实他们知道指定的是否是类型,于是提议将typename变为可选项,只在编译器无法确定的语境下typename才是必选项。
这项提议内容最终加入了C++20,因此,C++20编写模板代码将会进一步简化。
举个例子,C++20可以这样写代码:

1#include <iostream>
2
3struct S {
4    using X = int;
5    using R = char;
6};
7
8
9// 类模板
10template<class T,
11         auto F = typename T:
:X{}>    // 需要typename
12struct Foo {       
13    using X2 = T::X;                  // 不需要typename
14    typedef T::X X3;                  // 不需要typename                 
15    T::X val;                         // 不需要typename
16
17    T::R f(T::X x) {                  // 不需要typename
18        typename T::X i;              // 需要typename
19        return static_cast<T::R>(x);  // 不需要typename
20    }                                 
21
22    auto g() -> T::R {                // 不需要typename
23    }                                 
24
25    template<class U = T::X>          // 不需要typename
26    void k(U);                        
27};                                    
28
29
30// 函数模板                           
31template<class T>                     
32T:
:R                                  // 不需要typename
33f(typename T::X x)                    // 需要typename
34{                                     
35    using X2 = T::X;                  // 不需要typename
36    typedef typename T::X X3;         // 需要typename
37    typename T::X val;                // 需要typename
38
39    typename T::R f();                // 需要typename
40    auto g() -> T::R;                 // 不需要typename
41    void k(typename T::X);            // 需要typename
42
43    auto lam = [](T::X) {};           // 不需要typename
44
45    return static_cast<T::R>(x);      // 不需要typename
46}
47
48int main()
49
{
50    Foo<S> foo;
51    f<S>(65);
52
53    return 0;
54}

示例基本列举了大多数使用typename的情境,其中许多情境下typename已不再需要。
这里解释一点,为何在类模板与函数模板中,有些情境相同,但是typename使用规则却并不相同呢?
回答这个问题,再次引用一下理解可变参数模板,在这篇文章中我抛出了一个观点:函数模板处理的是数值,类模板处理的是类型。
在「类作用域」和「函数作用域」下编译器对于嵌套类型的解析形式是不一样的,前者解析为类型,后者解析为非类型。因此,在函数模板里许多地方依旧需要使用typename,而在类模板里则不必要。
总之就是,仍旧需要使用typename的地方都可能存在歧义,所以需要借助typename来标识其为类型。
此外,这里还有一个有趣的点。
Modern C++中建议使用using代替typedef来定义类型别名,以前二者除了写法似乎并不区别。
但是现在,使用using定义嵌套类型的别名时不用指定typename,而typedef仍然需要。因此,using代替typedef绝对是一种比较好的做法。

- EOF -

推荐阅读  点击标题可跳转

1、谈谈协程的历史与现状

2、中美程序员不完全对比

3、容器网络|深入理解 Cilium


关注『CPP开发者』

看精选C/C++技术文章 

点赞和在看就是最大的支持❤️

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存