const auto&和auto&if引用对象是const之间的区别

时间:2018-09-06 12:27:51

标签: c++ const auto

// 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;autoint替换)?而在情况2中,autoconst int取代了?

5 个答案:

答案 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)。

cpp-reference states

  

关键字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,则意图要更清楚地说明。因此,在这种情况下,我显然会更喜欢。