2012-05-17 28 views
6

Tôi biết điều này là không thể trong C++ 03, nhưng tôi hy vọng có một số voodoo mới cho phép tôi làm điều này. Xem bên dưới:Có anyway trong C++ 11 để có được loại con trỏ thành viên trong một mẫu?

template <class T> 
struct Binder 
{ 
    template<typename FT, FT T::*PtrTomember> 
    void AddMatch(); 
}; 
struct TestType 
{ 
    int i; 
}; 
int main(int argc, char** argv) 
{ 
    Binder<TestType> b; 
    b.AddMatch<int,&TestType::i>(); //I have to do this now 
    b.AddMatch<&TestType::i>(); //I'd like to be able to do this (i.e. infer field type) 
} 

Có cách nào để thực hiện việc này trong C++ 11 không? Liệu decltype có giúp được không?

** UPDATE: Sử dụng ví dụ Vlad của tôi đã suy nghĩ một cái gì đó như thế này sẽ làm việc (caveat: Tôi đã không được biên dịch như tôi đang xây dựng trình biên dịch với sự hỗ trợ decltype nay)

template <class T> 
struct Binder 
{ 
    template<typename MP, FT ft = decltype(MP)> 
    void AddMatch() 
    { 
     //static_assert to make sure MP is a member pointer of T 
    } 
}; 
struct TestType 
{ 
    int i; 
}; 
int main() 
{ 
    Binder<TestType> b; 
    b.AddMatch<&TestType::i>(); 
} 

Sẽ làm việc này?

+2

Cho rằng bạn đang xác định rõ ràng nó, tôi nghi ngờ có một cách. Nó sẽ hoạt động ngay cả trong C++ 03 nếu nó là 'AddMatch (& TestType :: i)' thay thế. –

+2

Bạn cần làm gì với con trỏ tới thành viên? Nó có thể là có một giải pháp tốt hơn so với việc sử dụng một con trỏ tới thành viên như một tham số mẫu không kiểu. – bames53

Trả lời

3

Điều bạn đang cố gắng làm không thể thực hiện được, nghĩa là bạn không thể sử dụng con trỏ thành viên làm biểu thức liên tục trừ khi bạn có loại. Tức là, kiểu của một đối số mẫu không phải kiểu được cung cấp, hoặc nói cách khác, không có suy luận kiểu cho các đối số mẫu.

+0

Thực ra tôi nghĩ Vlad đang đi đúng hướng. Tôi sẽ chơi với khái niệm của anh ấy một chút và xem nó có phù hợp với những gì tôi đang làm ... – Jaime

+0

@Jaime: Bạn có chắc không? Trong mã của Vlad, đối số cho khuôn mẫu chỉ là * type * của hàm thành viên, nhưng hàm thành viên không được chuyển thành đối số mẫu. Nếu bạn muốn có con trỏ thành viên như một hằng số thời gian biên dịch, bạn sẽ cần phải gọi nó như sau: 'b.AddMatch ();', là thậm chí còn cồng kềnh hơn trừ khi bạn giấu nó đằng sau một macro (mà tôi không hoàn toàn thích một ý tưởng). Nếu bạn không nhớ có con trỏ tới thành viên như là một giá trị thời gian chạy, thì bạn có thể chuyển nó tới hàm và trình biên dịch sẽ suy ra nó, nhưng điều đó thay đổi vấn đề. –

+0

...đó là những gì kballo đã chỉ ra trong phần bình luận cho câu hỏi của bạn. –

0
template <class T> 
struct Binder 
{ 
    template<typename FT> 
    void AddMatch(); 
}; 

struct TestType 
{ 
    int i; 
}; 

int main() 
{ 
    Binder<TestType> b; 
    b.AddMatch<decltype(&TestType::i)>(); 
} 
+0

Yea, điều đó sẽ làm việc tôi đặt cược, nhưng tôi muốn ngăn người dùng của tôi phải chỉ định decltype. Tôi đoán tôi có thể buộc FT là một thành viên lĩnh vực với những đặc điểm và tạo ra một param liên tục mà grabs decltype (& TestType: i) ... – Jaime

+0

Điều này không hoạt động. Thông số mẫu từ câu hỏi là thông số mẫu không phải kiểu. Hàm AddMatch được tham số hóa trên một con trỏ tới thành viên, không phải trên kiểu của một con trỏ tới thành viên. – bames53

+0

Điều này không giải quyết được vấn đề ban đầu, nó chỉ thay thế đối số đầu tiên 'int' bằng' decltype (& TestType :: i) 'nhiều hơn (và quên cung cấp con trỏ thực tế cho thành viên làm đối số mẫu thứ hai ...) Ở đâu trong mã ban đầu 'TestType :: i' là một giá trị đã biết, trong câu trả lời này giá trị thực tế biến mất (chỉ có kiểu là có) –

2

Làm thế nào về vấn đề này (như là một kicker nó hoạt động trong C++ 03):

#include <iostream> 
#include <typeinfo> 

template< typename T > struct ExtractMemberTypeHelper; 
template< typename R, typename T > 
struct ExtractMemberTypeHelper< R(T::*) > 
{ 
    typedef R Type; 
    typedef T ParentType; 
}; 

template< typename T > 
struct ExtractMemberType : public ExtractMemberTypeHelper<T> {}; 

struct foo 
{ 
    int bar; 
    template< typename T > 
    void func(const T& a_Arg) 
    { 
     std::cout << typeid(typename ExtractMemberType<T>::Type).name() << " " << typeid(typename ExtractMemberType<T>::ParentType).name() << std::endl; 
    } 
}; 

int main() 
{ 
    foo inst; 
    inst.func(&foo::bar); 
} 
+0

Đây là ý kiến ​​của hai ý kiến: thay đổi đối số mẫu thành đối số hàm. Sẽ tốt nếu bạn không cần/muốn con trỏ tới thành viên làm đối số mẫu ... –

+0

Ah, đúng vậy. Tôi hoàn toàn không thấy bất kỳ lợi ích nào của giao diện mà người đăng muốn sử dụng tuy nhiên so với chỉ chuyển nó như một đối số cho loại khấu trừ. – Ylisar

+0

Vâng, mã được tạo có thể hơi nhanh hơn trong trường hợp đối số mẫu, vì trình biên dịch có thể tiêm cuộc gọi chính xác thay vì gửi thông qua con trỏ, nhưng như bạn nói, trong hầu hết các trường hợp, nó sẽ không tạo sự khác biệt. +1 –

2

Bạn có thể làm cho "T" cung cấp thông tin này.

template <class ...T> 
struct BoundTypes { }; 

template <class U, class T> 
struct BinderDecls { 
    void AddMatch(); 
}; 

template <class U, class T, class ...Ts> 
struct BinderDecls<U, BoundTypes<T, Ts...>> 
    :BinderDecls<U, BoundTypes<Ts...>> 
{ 
    using BinderDecls<U, BoundTypes<Ts...>>::AddMatch; 

    template<T U::*PtrTomember> 
    void AddMatch(); 
}; 

template <class T> 
struct Binder : BinderDecls<T, typename T::bound_types> 
{ } 

Sau đó, nó trở nên dễ dàng

struct TestType { 
    typedef BoundTypes<int, float> bound_types; 

    int i; 
    float j; 
}; 

int main(int argc, char** argv) 
{ 
    Binder<TestType> b; 
    b.AddMatch<&TestType::i>(); 
    b.AddMatch<&TestType::j>(); 
} 

Hoặc bạn có thể sử dụng các định nghĩa hàm friend

template <class ...T> 
struct BoundTypes { }; 

template <class U, class T> 
struct BinderDecls { 
    template<T U::*ptr> 
    friend void addMatch(BinderDecl &u) { 
    // ... 
    } 
}; 

template <class U, class ...Ts> 
struct BinderDecls<U, BoundTypes<Ts...>> : BinderDecls<U, Ts>... 
{ }; 

template<typename = void> 
void addMatch() = delete; 

template <class T> 
struct Binder : BinderDecls<T, typename T::bound_types> 
{ } 

Sau đó, bạn có thể viết

struct TestType { 
    typedef BoundTypes<int, float> bound_types; 

    int i; 
    float j; 
}; 

int main(int argc, char** argv) 
{ 
    Binder<TestType> b; 
    addMatch<&TestType::i>(b); 
    addMatch<&TestType::j>(b); 
} 
Các vấn đề liên quan