// case 1
const int i = 42;
const auto &k = i;
// case 2
const int i = 42;
auto &k = i;
在这种情况下,在const
之前需要auto
关键字吗?毕竟,对自动推导类型的引用(k
)将包含对象( const
的顶级const
> int i
)。因此,我相信在两种情况下,k
都是对常量(const int &k
)的引用。
如果是这样,是否意味着情况1中的const auto &k = i;
被编译器替换为const int &k = i;
(auto
被int
替换)?而在情况2中,auto
被const int
取代了?
答案 0 :(得分:19)
auto
关键字会在编译时自动确定变量的类型。
在第一种情况下,auto
减少为int
,在第二种情况下减少为const int
。因此,您的两种情况都被简化为以下相同的代码:
const int &k = i;
但是,最好显式地使用const以提高可读性,并确保变量 TRULY 为const
。
答案 1 :(得分:4)
使用auto
进行类型推导的工作方式类似于模板参数类型推导,但有一些例外在给定示例中不适用。因此
const int i = 42;
const auto& k1 = i; // same as const int& k1 = i;
auto& k2 = i; // same as (const int)& k2 = i;
尽管如此,添加const
限定词可能更容易理解。
这是另一个示例,其中偏爱auto
的简洁性会引起误解:
int *i;
const auto k1 = i; // same as int* const k1 = i;
const auto *k2 = i; // same as const int *k2 = i;
在第一种情况下,i
指向的对象可以通过k1
进行修改,在第二种情况下,则不能。
答案 2 :(得分:2)
接受的答案是正确的,即编译结果没有区别。需要注意的重要一点是, auto&
版本是耦合 const
引用的k
引用与const
引用i
的值。我认为问题的标题是“ const auto&和auto&... 之间的区别”,因此在这里强调实用的区别很重要,如果您不提出{{1 }}关键字,您不能保证引用具有此 cv资格。在某些需要这样做的情况下,为什么要让它const
将来会保留在i
上呢?
答案 3 :(得分:2)
您好,欢迎堆栈溢出。
如这个小测试程序所示,无论您如何指定CLLocation *newLocation = [locations objectAtIndex:0];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *placemark = [placemarks lastObject];
NSLog(@"Postal code %@",placemark.postalCode);
}];
的类型,编译器都不会让您失去k
的常数。
i
预期结果:
#include <iostream>
#include <type_traits>
#include <string>
#define XSTR(s) STR(s)
#define STR(s) #s
template<class T>
struct type;
template<>
struct type<int>
{
static std::string name() { return "int"; }
};
template<class T>
struct type<T&&>
{
static std::string name() { return type<T>::name() + " &&"; }
};
template<class T>
struct type<T&>
{
static std::string name() { return type<T>::name() + " &"; }
};
template<class T>
struct type<T const>
{
static std::string name() { return type<T>::name() + " const"; }
};
#define REPORT_CONST(decl, var, assign) \
{ \
decl var = assign; \
do_it(STR(decl var = assign;), var); \
}
template<class Var>
void do_it(const char* message, Var&&)
{
std::cout << "case: " << message << " results in type: " << type<Var>::name() << '\n';
}
int main()
{
const int i = 42;
REPORT_CONST(const auto &, k, i);
REPORT_CONST(auto &, k, i);
REPORT_CONST(auto &&, k, std::move(i));
REPORT_CONST(auto const &&, k, std::move(i));
REPORT_CONST(int const&, k, i);
// REPORT_CONST(int &, k, i); // error: binding reference of type 'int&' to 'const int' discards qualifiers
}
http://coliru.stacked-crooked.com/a/7c72c8ebcf42c351
还要注意命名的r值到l值的衰减。
答案 4 :(得分:1)
在第一种情况下,auto
会被推导为const int
,在第二种情况下会是int
,这会有细微的差别(正如您明确指出的const)。
关键字auto可能附带修饰符,例如const或&,它们将参与类型推导。例如,给定const auto&i = expr ;,如果编译了函数调用f(expr),则i的类型恰好是虚构模板模板void f(const U&u)中参数u的类型。因此,可以根据初始化程序将auto &&推导为左值引用或右值引用,该初始化器用于基于范围的for循环中。
所以对您来说,这意味着
// case 1
const int i = 42;
const auto &k = i; // auto -> int
// case 2
const int i = 42;
auto &k = i; // auto -> const int
但是,在我看来,更重要的是,如果您明确声明const并保证了constness,则意图要更清楚地说明。因此,在这种情况下,我显然会更喜欢。