auto* 的类型推导规则是什么?
What are the type deduction rules for auto*?
auto*
的类型推导规则是什么?
考虑以下几点:
int x = 64;
int* px = &x;
auto* v1 = &x; // auto => ??? ok v1 is int* ...
auto* v2 = px; // auto => ??? is v2 int* ?
auto* v3 = &px; // auto => ??? is v3 int** ?
如果我们将类型推导分为两步,只是为了澄清我的问题:
- 在没有 (
*
) 的情况下推导“auto
”本身的类型 ... 然后
- 在添加 (
*
) 之后推断对象的类型 (v1
、v2
和 v3
)
所以我的两个问题是:
- 如果没有 (
*
),auto
会推导出什么?
-
v2
会指向 int
(int*
) 并且 v3
会指向指针 (int**
) 吗?
auto
将推导出给定表达式的 cv 限定类型。 auto*
将推导出表达式指向的类型的 cv 限定类型 - 如果表达式是指针 - 否则将无法编译。
对于给定的示例,v
的实际类型将是 pointer to int
,与 v2
相同,对于 v3
,它将是 pointer to pointer to int
。
如果您的第一个示例写成 auto v1 = &px
,v1 的类型将保持不变。
推导过程与模板参数相同。如果我这样做:
int a = 0;
auto* b = &a;
b
的类型将为 int*
。并写作:
auto b = &a;
将产生相同的类型,int*
。
在您的示例中,编译器将以某种方式添加缺失的星号。但最简单的形式是只写 auto
您可以使用 typeid
来回答您的问题。
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
// your code goes here
int x = 64;
int* px = &x;
auto* v1 = &x;
auto* v2 = px;
auto* v3 = &px;
cout<<typeid(v1).name()<<endl;
cout<<typeid(v2).name()<<endl;
cout<<typeid(v3).name()<<endl;
return 0;
}
输出:
Pi
Pi
PPi
Pi --> 指向整型变量的指针
PPi --> 指向整数变量的指针
如果您了解 模板类型推导 ,您将几乎了解 auto
类型推导 的所有内容。因为自动类型推导像模板类型推导一样工作。
当使用 auto
声明变量时,auto
在模板中充当 T
,类型说明符充当 参数类型 :
const auto i = 20;
将转换为:
template<typename T>
void func(const T param) { ... }
// ^^^^^^^
并参考:
const auto& j = i;
转换为:
template<typename T>
void func(const T& param)
// ^^^^^^^^
有了指针,也一样:
auto* v1 = &x;
变成
template<typename T>
void func(T* param)
因为x
是一个int
,那么auto* == int*
。
auto* v2 = px;
也是 int*
现在,你有第三个:
auto* v3 = &px;
变成 int**
因为你正在获取指针的地址。
template<typename T>
void func(T** param)
// ^^^
查看 auto 类型的一种简便方法是使用其他人提到的 typeid()
函数。
但我喜欢使用 <boost/type_index.hpp>
来正确显示类型:
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using namespace boost::typeindex;
int main()
{
int x = 64;
int* px = &x;
auto* v1 = &x;
auto* v2 = px;
auto* v3 = &px;
cout << type_id_with_cvr<decltype(v1)>().pretty_name() << '\n';
cout << type_id_with_cvr<decltype(v2)>().pretty_name() << '\n';
cout << type_id_with_cvr<decltype(v3)>().pretty_name() << '\n';
}
输出:
int*
int*
int**
自动类型推导和模板类型推导有一个重要区别,即std::initializer_list<>
考虑这些例子:
auto i = 1; // int
auto j(1); // int
auto k = { 1 }// std::initializer_list<int> !
auto l { 1 } // std::initializer_list<int> !
如您所见,将大括号初始化程序与 auto 一起使用可能会很麻烦。
但是,您可以在大括号之前手动编写类型以确保类型正确,但我不明白其中的意义:
auto i = int{ 1 }; // type is int
Clang 3.8 中已经实现了 new auto rules,这使得使用直接列表初始化和自动(即将发布的标准)成为可能
auto*
的类型推导规则是什么?
考虑以下几点:
int x = 64;
int* px = &x;
auto* v1 = &x; // auto => ??? ok v1 is int* ...
auto* v2 = px; // auto => ??? is v2 int* ?
auto* v3 = &px; // auto => ??? is v3 int** ?
如果我们将类型推导分为两步,只是为了澄清我的问题:
- 在没有 (
*
) 的情况下推导“auto
”本身的类型 ... 然后 - 在添加 (
*
) 之后推断对象的类型 (
v1
、v2
和 v3
)
所以我的两个问题是:
- 如果没有 (
*
),auto
会推导出什么? -
v2
会指向int
(int*
) 并且v3
会指向指针 (int**
) 吗?
auto
将推导出给定表达式的 cv 限定类型。 auto*
将推导出表达式指向的类型的 cv 限定类型 - 如果表达式是指针 - 否则将无法编译。
对于给定的示例,v
的实际类型将是 pointer to int
,与 v2
相同,对于 v3
,它将是 pointer to pointer to int
。
如果您的第一个示例写成 auto v1 = &px
,v1 的类型将保持不变。
推导过程与模板参数相同。如果我这样做:
int a = 0;
auto* b = &a;
b
的类型将为 int*
。并写作:
auto b = &a;
将产生相同的类型,int*
。
在您的示例中,编译器将以某种方式添加缺失的星号。但最简单的形式是只写 auto
您可以使用 typeid
来回答您的问题。
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
// your code goes here
int x = 64;
int* px = &x;
auto* v1 = &x;
auto* v2 = px;
auto* v3 = &px;
cout<<typeid(v1).name()<<endl;
cout<<typeid(v2).name()<<endl;
cout<<typeid(v3).name()<<endl;
return 0;
}
输出:
Pi
Pi
PPi
Pi --> 指向整型变量的指针
PPi --> 指向整数变量的指针
如果您了解 模板类型推导 ,您将几乎了解 auto
类型推导 的所有内容。因为自动类型推导像模板类型推导一样工作。
当使用 auto
声明变量时,auto
在模板中充当 T
,类型说明符充当 参数类型 :
const auto i = 20;
将转换为:
template<typename T>
void func(const T param) { ... }
// ^^^^^^^
并参考:
const auto& j = i;
转换为:
template<typename T>
void func(const T& param)
// ^^^^^^^^
有了指针,也一样:
auto* v1 = &x;
变成
template<typename T>
void func(T* param)
因为x
是一个int
,那么auto* == int*
。
auto* v2 = px;
也是 int*
现在,你有第三个:
auto* v3 = &px;
变成 int**
因为你正在获取指针的地址。
template<typename T>
void func(T** param)
// ^^^
查看 auto 类型的一种简便方法是使用其他人提到的 typeid()
函数。
但我喜欢使用 <boost/type_index.hpp>
来正确显示类型:
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using namespace boost::typeindex;
int main()
{
int x = 64;
int* px = &x;
auto* v1 = &x;
auto* v2 = px;
auto* v3 = &px;
cout << type_id_with_cvr<decltype(v1)>().pretty_name() << '\n';
cout << type_id_with_cvr<decltype(v2)>().pretty_name() << '\n';
cout << type_id_with_cvr<decltype(v3)>().pretty_name() << '\n';
}
输出:
int*
int*
int**
自动类型推导和模板类型推导有一个重要区别,即std::initializer_list<>
考虑这些例子:
auto i = 1; // int
auto j(1); // int
auto k = { 1 }// std::initializer_list<int> !
auto l { 1 } // std::initializer_list<int> !
如您所见,将大括号初始化程序与 auto 一起使用可能会很麻烦。
但是,您可以在大括号之前手动编写类型以确保类型正确,但我不明白其中的意义:
auto i = int{ 1 }; // type is int
Clang 3.8 中已经实现了 new auto rules,这使得使用直接列表初始化和自动(即将发布的标准)成为可能