2011-12-17 39 views
51

Khi tôi sử dụng C++ 11 auto, các quy tắc loại khấu trừ liên quan đến việc liệu nó sẽ giải quyết thành giá trị hoặc tham chiếu?C++ 11 ngữ nghĩa "tự động"

ví dụ, đôi khi nó là rõ ràng:

auto i = v.begin(); // Copy, begin() returns an iterator by value 

Đây là chưa rõ ràng:

const std::shared_ptr<Foo>& get_foo(); 
auto p = get_foo(); // Copy or reference? 

static std::shared_ptr<Foo> s_foo; 
auto sp = s_foo; // Copy or reference? 

std::vector<std::shared_ptr<Foo>> c; 
for (auto foo: c) { // Copy for every loop iteration? 

Trả lời

58

Nguyên tắc rất đơn giản: đó là cách bạn khai báo nó.

int i = 5; 
auto a1 = i; // value 
auto & a2 = i; // reference 

dụ Tiếp theo chứng minh điều đó:

#include <typeinfo> 
#include <iostream>  

template< typename T > 
struct A 
{ 
    static void foo(){ std::cout<< "value" << std::endl; } 
}; 
template< typename T > 
struct A< T&> 
{ 
    static void foo(){ std::cout<< "reference" << std::endl; } 
}; 

float& bar() 
{ 
    static float t=5.5; 
    return t; 
} 

int main() 
{ 
    int i = 5; 
    int &r = i; 

    auto a1 = i; 
    auto a2 = r; 
    auto a3 = bar(); 

    A<decltype(i)>::foo();  // value 
    A<decltype(r)>::foo();  // reference 
    A<decltype(a1)>::foo();  // value 
    A<decltype(a2)>::foo();  // value 
    A<decltype(bar())>::foo(); // reference 
    A<decltype(a3)>::foo();  // value 
} 

Sản lượng:

value 
reference 
value 
value 
reference 
value 
+5

Lưu ý rằng con trỏ '//' không thực sự cần thiết. Ngoài ra, chỉ vì một trình biên dịch cho đầu ra này không có nghĩa là nó phù hợp tiêu chuẩn. ;) Trong trường hợp này nó là chính xác, mặc dù một lời giải thích tốt hơn có thể được đưa ra những gì chính xác xảy ra (loại suy luận là "phân rã"). – Xeo

12

§7.1.6.4 [dcl.spec.auto] p6

Khi loại một declarator-id đã được xác định d theo 8.3, loại biến được khai báo sử dụng mã khai báo được xác định từ loại trình khởi tạo của nó bằng cách sử dụng quy tắc khấu trừ đối số mẫu.

Điều này có nghĩa là không có gì khác hơn là auto khấu trừ đối số mẫu mô hình trong khi gọi hàm.

template<class T> 
void f(T){} // #1, will also be by-value 

template<class T> 
void g(T&){} // #2, will always be by-reference 

Lưu ý rằng # 1 sẽ luôn sao chép đối số đã qua, bất kể bạn chuyển tham chiếu hay bất kỳ điều gì khác. (Trừ khi bạn chỉ định cụ thể đối số mẫu như f<int&>(intref);.)

+0

Vậy chính xác điều này có ý nghĩa gì đối với các vòng lặp dựa trên dải ô? Tôi mặc dù nó có nghĩa là họ là do tham khảo (mà có vẻ hợp lý với tôi), nhưng chỉ phát hiện ra rằng điều này đã không xảy ra trong một trường hợp. – leftaroundabout

+3

@leftaroundabout: Điều đó không hợp lý. 'Tự động' chỉ hoạt động giống nhau. 'for (auto val: range)' sẽ luôn luôn sao chép, 'for (auto & ref: range)' sẽ luôn là một tham chiếu. Và để gây nhầm lẫn hơn nữa 'for (auto && x: range)' sẽ là 'T &&' hoặc 'T &' phụ thuộc vào việc '* bắt đầu (phạm vi)' sẽ trả về một giá trị hay một tham chiếu. – Xeo

9

Bất kể bạn nhận được gì từ bên phải (của "=") không bao giờ là tham chiếu. Cụ thể hơn là kết quả của một biểu thức không bao giờ là một tham chiếu. Trong ánh sáng này, lưu ý sự khác biệt giữa các kết quả trong ví dụ.

#include <typeinfo> 
#include <iostream> 

template< typename T > 
struct A 
{ 
    static void foo(){ std::cout<< "value" << std::endl; } 
}; 

template< typename T > 
struct A< T&> 
{ 
    static void foo(){ std::cout<< "reference" << std::endl; } 
}; 

float& bar() 
{ 
    static float t=5.5; 
    return t; 
} 

int main() 
{ 
    auto a3 = bar(); 

    A<decltype(bar())>::foo(); // reference 
    A<decltype(a3)>::foo(); // value 
} 
+0

Vui lòng bao gồm phần còn lại của ví dụ! Đây là câu trả lời ngắn gọn nhất nhưng bạn cần phải đọc câu trả lời khác để hiểu nó ... – povman

+0

Câu đầu tiên đó chính là điều tôi đang tìm kiếm. Cảm ơn. –

Các vấn đề liên quan