Cảm ơn bài viết của bạn, mình có chút thắc mắc như sau: Nếu sử dụng hàm https://bugs.vn/io/ZvGA

thì trình biên dịch báo lỗi, nhưng nếu để cả 2 biến là auto thì C++14 lại nhận được, bạn có thể giải thích giúp mình được không? https://bugs.vn/io/oOGW

C++14 template dựa vào các thông tin cần có để tạo ra các hàm đó.

Tham khảo: https://bugs.vn/io/ZvGAhttps://bugs.vn/io/oOGW

C++14 chưa hỗ trợ cho việc truyền tham số dạng auto vào hàm.

Đúng thế, mình đang dùng gcc bạn ạ. Mình còn chút thắc mắc về template type deduction, muốn dùng auto thì phải hiểu chắc type deduction nhưng mình còn khá mù mờ về khái niệm này, bạn có thể chỉ mình sâu hơn về type deduction được không.

Mình có đọc thêm một số sách nhưng tiếng anh ko tốt nên ko hiểu rõ dc.

Cảm ơn bạn!

Với khái niệm typde deduction nếu hiểu cao siêu thì chỉ thiệt thòi cho mình, nhưng nó rất là "trần trụi". Bạn chỉ cần hiểu đơn giản như sau, đó là khả năng của trình biên dịch khi nó thấy được kiểu dữ liệu đầu tiên return trong các dòng code mà nó quét từ trên xuống trong hàm.

Nếu nó thấy được giá trị hoặc biến trả về kiểu gì, thì nó sẽ tự sinh ra cái hàm tương ứng có kiểu trả về tương ứng kiểu như vậy.

Hôm qua mình có ngồi đọc lại và có note lại một số ý sau về template, thực sự là khá lằng nhằng

template

void f(ParamType param);

f(expr);

Khi compile, compiler sẽ dùng expr để deduce (suy luận) hai kiểu T và ParamType.

Type của T không chỉ phụ thuộc vào type của expr và còn phụ thuộc vào form của ParamType. Có ba trường hợp:

- ParamType là một pointer hoặc reference, nhưng không phải là universal reference

- ParamType là một universal reference

- ParamType không phải pointer hoặc reference (kiểu pass-by-value)

Case 1: ParamType là reference hoặc pointer

Trong trường hợp này, type deduction hoạt động như sau:

- Nếu expr là reference thì bỏ qua phần reference này.

- Dựa vào kiểu của expr và ParamType để xác định T.

Ví dụ:

template

void f(T& param);

int x = 27;

cons tint cx = x;

const int& rx = x;

f(x); //T là int, kiểu của param là int&

f(cx); //T là const int, kiểu của param là const int&

f(rx); //T là const int mặc dù expr là int& do bỏ qua reference

//Kiểu của param là const int&

Ở f(cx) và f(rx) parameter là một const, khi deduce thì constness của nó vẫn giữ nguyên và được deduce cho T. Khác với case 3 khi ParamType không phải là pointer hay reference, ở case 3 constness và reference-ness bị bỏ qua khi deduce.

Nếu đổi kiểu tham số truyền vào của f từ T& sang const T& thì constness của cx và rx vẫn được giữ nguyên, ở x khi deduce sẽ là const vì ParamType là const T&. Nghĩa là không cần quan tâm đến T có là const hay không, khi deduce thì param đều có kiểu là reference-to-const.

template

void f(const T& param);

int x = 27;

cons tint cx = x;

const int& rx = x;

f(x); //T là int, kiểu của param là const int&

f(cx); //T là int, kiểu của param là const int&

f(rx); //T là int mặc dù expr là int& do bỏ qua reference

//Kiểu của param là const int&

Với pointer cũng tương tự:

template

void f(T* param);

int x = 27;

const int *px = &x;

f(&x); //T là int, kiểu của param là int*

f(px); //T là const int, kiểu của param là const int*

Case 2: ParamType là universal reference

template

void f(T& param);

Parameter được khai báo giống như rvalue reference (T&&) nhưng sẽ hoạt động khác khi lvalue argument được truyền vào. Trong trường hợp nào type deduction hoạt động như sau:

- Nếu expr là một lvalue, cả T và ParamType đều được deduce là lvalue reference.

- Nếu expr là một rvalue, thì T và ParamType được deduce bình thường.

Ví dụ:

template

void f(T&& param);

int x = 27;

const int cx = x;

const int& rx = x;

f(x); //x là lvalue, T là int&, kiểu của param là int&

f(cx); //cx là lvalue, T là int&, kiểu của param là const int&

f(rx); //rx là lvalue, T là const int&

//kiểu của param là const int&

f(27); //27 là rvalue, T là int, kiểu của param là int&&

Case 3: ParamType không phải là pointer hay reference

template

void f(T param);

Trong trường hợp này param sẽ copy expr truyền vào vào một object mới. Type deduction hoạt động như sau:

- Nếu expr là reference thì bỏ qua phần reference.

- Sau khi ignore reference-ness, nếu expr là constness cũng bị ignore.

Ví dụ:

template

void f(T param);

int x = 27;

cons tint cx = x;

const int& rx = x;

f(x); //T là int, kiểu của param là int

f(cx); //T là int, kiểu của param là int

f(rx); //T là int, kiểu của param là int

Trong trường hợp này mặc dù cx và rx đều là const nhưng param không phải là const vì param là một object hoàn toàn độc lập với cx và rx, nó là một bản copy của cx và rx, param không thể thay đổi được cx và rx. Đó cũng là lý do vì sao constness của expr được ignore.

Ví dụ:

template

void f(const T param);

int x = 27;

const int cx = x;

const int& rx = x;

f(x); //T là int, kiểu của param là const int

f(cx); //T là int, kiểu của param là const int

f(rx); //T là int, kiểu của param là const int

Nếu expr là một const pointer đến một const object

template

void f(T param); // param passed by value

const char* const ptr ="Fun with pointers"; // ptr là const pointer đến một const object

f(ptr);

Học đánh phím nhanh liên quan tới việc làm thơ ra sao thì học lập trình liên quan đến việc thiết kế phần mềm cũng như vậy. Ted Nelson