TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

typedef using

参考

知无涯之C++ typename的起源与用法

为什么必须在何处以及为什么要放置“模板”和“类型名”关键字?

effective modern c++

wikipedia typedef

wikipedia typename

c++11FAQ

typedef

在C和C++编程语言中,typedef是一个关键字。它用来对一个数据类型取一个别名,目的是为了使源代码更易于阅读和理解。它通常用于简化声明复杂的类型组成的结构 ,但它也常常在各种长度的整数数据类型中看到,例如size_t和time_t。

定义数组

1
2
3
4
5
6
typedef char arrType[6];    // type name: arrType
// new type: char[6]

arrType arr={1,2,3,4,5,6}; // same as: char arr[6]={1,2,3,4,5,6}

arrType *pArr; // same as: char (*pArr)[6];

定义函数指针

1
2
3
4
5
6
//old
void (*signal(int sig, void (*func)(int)))(int);

//new
typedef void (*sighandler_t)(int);
sighandler_t signal(int sig, sighandler_t func);

类型转换

1
2
3
4
5
6
7
8
9
10
11
//old
void *p = NULL;
int (*x)(double) = (int (*)(double)) p; // This is legal
int (*)(double) y = (int (*)(double)) p; // Left-hand side is not legal
int (*z)(double) = (int (*p)(double)); // Right-hand side is not legal

//new
typedef int (*funcptr)(double); // pointer to function taking a double returning int
funcptr x = (funcptr) NULL; // C or C++
funcptr y = funcptr(NULL); // C++ only
funcptr z = static_cast<funcptr>(NULL); // C++ only

using

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template<int>
// idea: int_exact_trait<N>::type用于表达含有N个bit的数值类型
struct int_exact_traits {
typedef int type;
};

template<>
struct int_exact_traits<8> {
typedef char type;
};

template<>
struct int_exact_traits<16> {
typedef char[2] type;
};

// ...

template<int N>
// 定义别名用以简化书写
// 译注:给模板的通用版本取别名,则其所有的特化版本自动获得该别名,
// 例如对于8bit的特化版本,现在可直接使用别名
using int_exact = typename int_exact_traits<N>::type;
// int_exact<8> 是含有8个bit的数值类型
int_exact<8> a = 7;

除了在模板方面身担重任外,using语法也可作为对普通类型定义别名的另一种选择(相较于typedef更合吾意)

1
2
3
typedef void (*PFD)(double);    // C 样式
using PF = void (*)(double); // using加上C样式的类型
using P = [](double)->void; // using和函数返回类型后置语法

typename

input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <typename T>
void foo(const T& t)
{
// 声明一个指向某个类型为T::bar的对象的指针
T::bar * p;
}

#if 1
struct StructWithBarAsType {
typedef int bar;
};
#endif

#if 0
struct StructWithBarAsValue {
int bar;
};
#endif

int main() {
StructWithBarAsType x;
foo(x);
}

output

错误    C3861    “p”: 找不到标识符    

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

意即出现上述歧义时(# if 0/ #if 1),编译器将自动默认bar为一个变量名,而不是类型名

解决方案:

1
2
3
4
5
6
template <typename T>
void foo(const T& t)
{
// 声明一个指向某个类型为T::bar的对象的指针
typename T::bar * p;
}

显示的说明T::bar是个类型

区别

1 typedef不能直接用于模板,需要具体化模板类型或者嵌套在struct里面:

1
2
3
4
5
6
7
8
9
template <typename T>
typedef vector<T> vecint; //error C2823 typedef 模板 非法

template <typename T>
struct vec {
typedef vector<T> vecint; //ok
};

typedef vector<int> vecint; //ok

2

  • c++带依赖型别前面加typename
  • typename仅允许在限定名称之前使用
1
2
3
4
5
6
7
8
9
10
11
12
template <typename T>
struct s1
{
typedef vector<T> type;
};

template <typename T>
struct s2
{
//typename typedef s1<T>::type type2; //ok
typedef s1<T>::type type2; //警告 C4346 “type”: 依赖名称不是类型
};

::这个是罪魁祸首,因为::有好几种解释:

  • 静态成员
  • 嵌套类/typedef

这种定义含糊的就需要手动加typename

3 使用using的时候,编译器知道后面的是一个型别的名字,就相当于隐士的加了typename.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "pch.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;

template <typename T>
struct s1
{
typedef vector<T> type;
};

template <typename T>
struct s2
{
//typename typedef s1<T>::type type2;
//typedef s1<T>::type type2;
using type2 = typename s1<T>::type;
};

template <typename T>
using t1 = vector<T>;

template <typename T>
using t2 = t1<T>;

template <typename T>
struct s3
{
//gcc error vs ok
using t3 = typename t1<T>; //gcc error:expected nested-name-specifier
//using type3 = t1<T>;
};

int main() {

}

4 支持c++11以后的话,优先选择using

ending

2020071201.jpg

----------- ending -----------