2012-07-31 30 views
14

Được biết, đối số mẫu có thể là con trỏ đến các hàm thành viên.Trích đối số mẫu cho các con trỏ hàm thành viên

Vì vậy, tôi có thể viết:

struct Bar 
{ 
    int fun(float x); 
}; 

template <int (Bar::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<&Bar::fun> FooBar; 

Nhưng nếu tôi muốn loại các Bar mình là một mẫu đối số:

template <typename B, int (B::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<Bar, &Bar::fun> FooBar; 

Bây giờ, khi tôi sử dụng nó, tôi phải viết Bar hai lần!

Câu hỏi của tôi là: Có cách nào để buộc trình biên dịch suy ra loại lớp tự động không?

Mục tiêu là cho điều này chỉ làm việc:

typedef Foo<&Bar::fun> FooBar; 
typedef Foo<&Moo::fun> FooMoo; 

Trả lời

5

Bạn có lẽ chỉ nên viết tên lớp trong đó. Tuy nhiên, nếu bạn thực sự muốn tránh rằng bạn có thể sử dụng ma thuật ác của macro. Các phiên bản đơn giản là nguy hiểm hơn:

#define TT(X) decltype(X), X 

template<typename T,T t> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

này sẽ chấp nhận bất kỳ loại phi kiểu mẫu tham số, và bạn có thể gặp khó khăn để hiểu lỗi nếu việc thực hiện Foo chỉ làm việc với thành viên con trỏ-to-.

Để làm cho nó một chút an toàn hơn bạn cần một metafunction cho bạn biết tên lớp:

template<typename T> struct member_ptr_traits; 

template<typename Class,typename Ret,typename... Args> 
struct member_ptr_traits<Ret (Class::*)(Args...)> 
{ 
    typedef Class class_type; 
    typedef Ret return_type; 
}; 

#define TT(X) member_ptr_traits<decltype(X)>::class_type , X 

template<typename T,int (T::*FUN)(float)> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

Ngoài ra cả hai sử dụng C++ 11 vì vậy họ sẽ không làm việc với các trình biên dịch cũ. Phiên bản đơn giản này có thể được viết lại để sử dụng các phần mở rộng biên dịch cũ typeof hoặc tương tự. Viết lại phiên bản an toàn hơn đòi hỏi phải mô phỏng các mẫu variadic.

+0

Thực ra, tôi đang sử dụng macro xấu xí cho điều này (đó là mẫu bên trong thư viện, vì vậy không có nguy cơ thực sự bị lạm dụng). Dù sao, 'member_ptr_traits' rất tuyệt vì tôi thực sự cần kiểu' T'. – rodrigo

7

đơn giản trả lời: không có không có.

Vấn đề là để typedef Foo<&Bar::fun> FooBar; hoạt động, mẫu sẽ phải có đối số không phải kiểu duy nhất, nhưng loại đối số đó sẽ không xác định khi mẫu được khai báo, không hợp lệ. Ở phía bên kia, loại khấu trừ không bao giờ được áp dụng cho các đối số của mẫu (chỉ với các đối số cho các mẫu chức năng, nhưng đó là các đối số cho hàm, không phải là mẫu).

+0

Đã hiểu. Vì vậy, nó sẽ là không thể cũng làm cho một chức năng mẫu, phải không? – rodrigo

+0

@rodrigo: Nếu bạn muốn lấy đối số mẫu đó như là một con trỏ thành viên có. Câu hỏi đặt ra là liệu bạn có cần con trỏ tới thành viên để trở thành đối số mẫu hay không, hoặc nó có thể là một đối số hàm, có thể được suy luận. –

+0

Có, tôi cần nó là đối số mẫu vì nó phải được sử dụng để tạo mẫu lồng nhau. Dù sao, cảm ơn bạn cho bạn cái nhìn sâu sắc – rodrigo

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