2011-08-09 22 views
36

Hãy xem xét các đoạn trích sau đây từ safe bool idiom:Có trường hợp nào mà typedef là hoàn toàn cần thiết không?

typedef void (Testable::*bool_type)() const; 
operator bool_type() const; 

Có thể khai báo hàm chuyển đổi mà không typedef? Các phần sau không biên dịch:

operator (void (Testable::*)() const)() const; 
+3

Tại sao bạn sẽ khai báo chức năng mà không có typedef? –

+0

Chuyển đổi sang bool an toàn có thực sự cần thiết không? –

+0

@Tad: Có vẻ như hữu ích trong trường hợp cụ thể của tôi (một mẫu tùy chọn 'tùy chọn '). – fredoverflow

Trả lời

9

Ah, tôi chỉ nhớ lại identity siêu chức năng. Có thể viết

operator typename identity<void (Testable::*)() const>::type() const; 

với định nghĩa sau đây của identity:

template <typename T> 
struct identity 
{ 
    typedef T type; 
}; 

Bạn có thể tranh luận rằng identity vẫn sử dụng một typedef, nhưng giải pháp này là "tốt" đủ cho tôi.

+0

Tôi sẽ trả lời đúng ... 'identity' là một cách hay để giải quyết các vấn đề phân tích cú pháp. –

+0

@David: Đáng buồn thay,' identity' không phải là một phần của tiêu chuẩn C++ 0x Trong trường hợp này, chúng ta có thể sử dụng 'std :: decay', mặc dù ... – fredoverflow

+0

Đó là một phiên bản tốt hơn về những gì tôi đã làm! – AJG85

2

Phân tích của tôi cho rằng không thể sử dụng được mà không sử dụng typedef. Trình biên dịch thấy ( làm mã thông báo đầu tiên và giả sử bạn đang quá tải () operator, không nên có bất kỳ đối số nào (Các đối số sẽ đến trong bộ ngoặc đơn tiếp theo). Đặt bất kỳ bộ ngoặc đơn phụ nào cũng sẽ không giúp ích gì - nhưng thực sự sẽ gây nhầm lẫn cho trình biên dịch và do đó đặt nhiều lỗi hơn.

Hầu hết mã STL nằm trên đầu trang của các lần nhập typedef và chúng tôi phải/phải sử dụng chúng!

1

A typedef không phải là macro mà ví dụ thứ hai của bạn không tương đương với ví dụ đầu tiên. Trong trường hợp đầu tiên, typedef của bạn xác định một hàm functor, sau đó sử dụng loại đó trong toán tử cast của loại functor. Trong lần thứ hai, toán tử sử dụng cú pháp không đúng vì không có toán tử nào được chỉ định vì không có kiểu nào. Tôi không chắc làm thế nào để viết nó nhưng có một cách thường.

Kiểu chữ không thực sự cần thiết ngoại trừ việc tạo mã có thể đọc được trong TMP và thậm chí sau đó nó phụ thuộc vào loại con người của bạn.

Vì tôi không thể đưa ra cú pháp thay thế, có thể typedef là cần thiết trong một số trường hợp. Tôi chỉ nghĩ về một người khác có thể. Giả sử bạn đã có một mẫu với chuyên ngành trong đó có một phương pháp tĩnh với một kiểu trả về như dưới đây:

template <typename T> 
struct WhateverHandler 
{ 
    typedef T rType; 
    static rType Whatever() { return rType(); } 
}; 

template <> 
struct WhateverHandler<std::string> 
{ 
    typedef std::string rType; 
    static rType Whatever() { return rType(); } 
}; 

Tôi nghĩ rằng trong trường hợp này cũng có thể bạn sẽ cần typedef để gọi phương thức tĩnh bất kể chuyên môn hóa như nếu không phương pháp có thể gây nhầm lẫn cho trình biên dịch vì các kiểu trả về sẽ khác nhau nhưng nó sẽ không phải là quá tải thích hợp.

template <typename T> 
struct WhateverUser 
{ 
    typename WhateverHandler<T>::rType DoWhatever() 
    { 
     return WhateverHandler<T>::template Whatever(); 
    } 
}; 
3

Một trường hợp (không liên quan đến câu hỏi của bạn), nơi một typedef được yêu cầu là khi sử dụng

va_arg() vĩ mô. Trích dẫn tiêu chuẩn C99 (7.15.1.1):

loại * va_arg (va_list ap, loại);

...

Tham số loại phải là một tên loại quy định như vậy mà các loại của một con trỏ đến một đối tượng mà đã loại quy định có thể đạt được chỉ đơn giản bằng một postfixing * để loại

+1

có một trường hợp như vậy, cụ thể là cuộc gọi của giả-destructor –

+0

Tức là 'p-> ~ unsigned char()' không được phép (đối với những người không biết một giả-destructor là gì hoặc tại sao bạn cần một typedef ở đó) – MSalters

3

trả lời là "có trường hợp một typedef là hoàn toàn cần thiết?"Từ tiêu đề câu hỏi, đây là một ví dụ về nơi typedef là cần thiết:

f(unsigned char()); // compiler error! 
typedef unsigned char Byte; 
f(Byte());   // fine! 

Xem kết quả ở đây:. http://ideone.com/JPUra

+0

Chiến dịch biên dịch lại GCC không thành công, VC thành công – Ajay

+1

Làm thế nào về 'f (identity :: type())'?;) – fredoverflow

+2

@FredOverflow có vẻ như nó sẽ hoạt động, mặc dù về mặt kỹ thuật 'type' là một typedef. : P –

2

Dường như ngữ pháp đòi hỏi sử dụng một typedef trong trường hợp của bạn Chuyển đổi -function-id phải có dạng hànhchuyển đổi loại-id. các chuyển đổi loại-id không thể chứa dấu ngoặc đơn. Vì vậy, bạn phải sử dụng typedef khi chuyển sang một loại con trỏ-to-hàm, hoặc thành kiểu hàm con trỏ tới thành viên .

+0

"Loại chuyển đổi-id không được chứa dấu ngoặc đơn". Bạn lấy cái đó từ đâu? – TonyK

+0

@TonyK: từ ngữ pháp. Về cơ bản nó có thể là kiểu nguyên gốc có thể là const/volatile hoặc một id đủ điều kiện (type-specifier-seq), theo sau là số không hoặc nhiều toán tử con trỏ (conversion-declarationator-opt). –

+0

@n: Tôi đã tìm được cách: 'mẫu lớp C {}; lớp S {operator C <(99)> *() {return 0; }}; ' – TonyK

2

Trong C++ 11, bạn có thể làm điều đó như thế này (gcc 4.5.2):

operator decltype((void (Testable::*)() const)(0))() const ; 

Tôi không nói rằng nó khá ...

+0

Chờ, tôi vừa thử nó trong VC10 và nó không hoạt động: (C2833 – fredoverflow

+0

Bạn đã thử với' decltype (& Testable :: foo) 'trong đó' foo' là một phương thức thành viên có chữ ký thích hợp không? –

+0

@ David: Yup, không hoạt động: (C2833 một lần nữa – fredoverflow

1

Tôi chỉ cần chạy qua vấn đề này, với kêu vang ++:

foo.cpp:17:8: error: must use a typedef to declare a conversion to 'void (*(int))()' 

và có một C++ 11 STL mẫu trong đó bao gồm bản sắc <T> chức năng:

#include <type_traits> 
… 
struct foo { 
    void bar() const { } 
    operator std::common_type<void(foo::*)()const>::type() { return &foo::bar; } 
}; 
Các vấn đề liên quan