Tại sao không bắt buộc phải sử dụng tên chữ cho các loại phụ thuộc trong trường hợp sau?


10

Tôi đã đọc về việc loại bỏ tham chiếu của một loại, ở đây .

Nó đưa ra ví dụ sau:

#include <iostream> // std::cout
#include <type_traits> // std::is_same

template<class T1, class T2>
void print_is_same() {
  std::cout << std::is_same<T1, T2>() << '\n';
}

int main() {
  std::cout << std::boolalpha;

  print_is_same<int, int>();
  print_is_same<int, int &>();
  print_is_same<int, int &&>();

  print_is_same<int, std::remove_reference<int>::type>(); // Why not typename std::remove_reference<int>::type ?
  print_is_same<int, std::remove_reference<int &>::type>();// Why not typename std::remove_reference<int &>::type ?
  print_is_same<int, std::remove_reference<int &&>::type>();// Why not typename std::remove_reference<int &&>::type ?
}

Các types trong các std::remove_referencetính trạng là loại phụ thuộc.

Có thể thực hiện

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

Nhưng tại sao nó không sử dụng typename std::remove_reference</*TYPE*/>::type?

Câu trả lời:


22

Các types trong các std::remove_referencetính trạng là loại phụ thuộc.

Không, họ không phải là tên phụ thuộc ở đây. Các đối số mẫu đã được chỉ định rõ ràng là int, int&int&&. Do đó, các loại được biết đến tại thời điểm này.

Mặt khác, nếu bạn sử dụng std::remove_referencevới một tham số mẫu, vd

template <typename T>
void foo() {
    print_is_same<int, typename std::remove_reference<T>::type>();
}

sau đó bạn phải sử dụng typenameđể nói rằng đó std::remove_reference<T>::typelà một loại vì biểu thức của bạn bây giờ phụ thuộc vào tham số mẫu T.


5

Tóm lại, bạn cần typenameđảm bảo trình biên dịch

std::remove_reference<int>::type

thực sự là một loại Hãy xem xét một số mẫu khác

template <typename T>
struct foo {
    using type = int;
};

Đây foo::typelà một loại. Nhưng nếu ai đó cung cấp một chuyên môn dọc theo dòng

template <> struct foo<int> {
    int type;
};

Bây giờ typekhông phải là một loại mà là một int. Bây giờ khi bạn sử dụng foo bên trong một mẫu:

template <typanem T> 
struct bar {
    using type = typename foo<T>::type;
};

Bạn phải đảm bảo trình biên dịch foo<T>::typethực sự là một kiểu, không phải cái gì khác, vì chỉ nhìn vào bar(và mẫu chính foo) trình biên dịch không thể biết điều đó.

Tuy nhiên, trong bạn mainnhững std::remove_reference<int>::typekhông phụ thuộc vào một tham số mẫu, do đó trình biên dịch có thể dễ dàng kiểm tra xem nó là một loại.


0

Các từ khóa typename được sử dụng để biên dịch giúp phân tích các nguồn. Nó chỉ ra id là tên loại, không phải tên biến hoặc tên phương thức. Nhưng trong các tình huống như trình biên dịch trên có thể tự tìm ra nó, vì vậy từ khóa này là không bắt buộc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.