2016-04-19 15 views
8

Tôi muốn kiểm tra xem biến thành viên của một lớp có tĩnh hay không. Sử dụng std :: is_member_pointer hoạt động tốt cho tất cả các loại trừ các thành viên tham chiếu.Loại đặc điểm: Kiểm tra xem biến thành viên tham chiếu có tĩnh hay không

#include <type_traits> 

struct A { 
    int foo; 
}; 

struct B : A {}; 

struct C { 
    static int foo; 
}; 

struct D : C { 
}; 

struct E { 
    int &foo; 
}; 

struct F { 
    static int &foo; 
}; 

static_assert(std::is_member_pointer<decltype(&A::foo)>::value, "No"); 
static_assert(std::is_member_pointer<decltype(&B::foo)>::value, "No"); 
static_assert(!std::is_member_pointer<decltype(&C::foo)>::value, "No"); 
static_assert(!std::is_member_pointer<decltype(&D::foo)>::value, "No"); 

// Fail to compile: 
static_assert(std::is_member_pointer<decltype(&E::foo)>::value, "No"); 

static_assert(!std::is_member_pointer<decltype(&F::foo)>::value, "No"); 

Live example.

Tôi hiểu sai, rằng một con trỏ không thể trỏ đến một thành viên tham khảo. Nhưng làm thế nào để tránh nó và vẫn còn phân biệt nếu nó là một biến tĩnh hoặc không tĩnh? Bất kỳ ý tưởng về điều đó?

+1

Related: http://stackoverflow.com/questions/8336274/pointer-to-member-that-is-a-reference-illegal – PiotrNycz

Trả lời

2

Bạn có thể thêm một dự phòng trong trường hợp &E::foo thất bại sử dụng SFINAE (và một số khác trong trường hợp E::foo không tồn tại ở tất cả):

template <typename T> 
std::is_member_pointer<decltype(&T::foo)> is_member_foo(int); 

template <typename T> 
decltype(T::foo, std::true_type{}) is_member_foo(long); 

template <typename T> 
std::false_type is_member_foo(...); 

template <typename T> 
using IsMemberFoo = decltype(is_member_foo<T>(0)); 

static_assert(IsMemberFoo<A>{}, "No"); 
static_assert(IsMemberFoo<B>{}, "No"); 
static_assert(!IsMemberFoo<C>{}, "No"); 
static_assert(!IsMemberFoo<D>{}, "No"); 
static_assert(IsMemberFoo<E>{}, "No"); 
static_assert(!IsMemberFoo<F>{}, "No"); 
static_assert(!IsMemberFoo<G>{}, "No"); // struct G { }; 

gì mã này không:

  • Nếu &T::foo là hợp lệ, nó sẽ kiểm tra xem thành viên có tĩnh hay không bằng cách sử dụng std::is_member_pointer (phiên bản của bạn).
  • Nếu &T::foo là không hợp lệ, nó rơi trở lại tình trạng quá tải thứ hai (ở đây bạn chắc chắn rằng foo không phải là tĩnh, hoặc quá tải đầu tiên sẽ được chọn):
    • Nếu T::foo là hợp lệ (thành viên tồn tại), nó trả về std::true_type.
    • Otherwize nó rơi trở lại quá tải cuối cùng và trả về std::false_type.

Cũng lưu ý (nhờ @iammilind) mà cho private thành viên, T::fookhông hợp lệ, vì vậy tình trạng quá tải thứ ba sẽ được chọn.

dụ làm việc trên ideone: http://ideone.com/FILHbK

ghi chú Side (giải thích mở rộng):

  • Khi &T::foo là hợp lệ, hai định nghĩa chồng đầu tiên là hợp lệ, nhưng một trong những đầu tiên được chọn từ int là chính xác phù hợp trong khi long thì không.
  • decltype(T::foo, std::true_type{}): T::foo chỉ ở đây để "để SFINAE" rơi trở lại tình trạng quá tải thứ ba nếu T::foo không hợp lệ, nhưng loại kết quả là std::true_type nhờ toán tử dấu phẩy.

Nếu bạn thích, bạn cũng có thể tạo ra một phiên bản generic (http://ideone.com/lzH2FB):

#define IsMember(MEM) \ 
template <typename T> \ 
std::is_member_pointer<decltype(&T::MEM)> is_member_##MEM(int); \ 
template<typename T> \ 
decltype(T::MEM, std::true_type{}) is_member_##MEM(long); \ 
template <typename T> \ 
std::false_type is_member_##MEM(...); \ 
template <typename T> \ 
using IsMember_##MEM = decltype(is_member_##MEM<T>(0)); 

// Instanciate IsMember_foo 
IsMember(foo); 

// Use it: 
static_assert(IsMember_foo<A>{}, "No"); 

Cũng xem hai câu trả lời này nếu bạn muốn để đóng gói tất cả mọi thứ trong một lớp học (mà không cần phải is_member_ chức năng) :

+0

Câu trả lời của bạn có vẻ đúng với tôi. Upvoted nó. Bạn có thể thực hiện một số thay đổi trong mã ví dụ không? 1. 'C' lặp lại hai lần, nhưng' D' không có ở đó. 2. Thay thế 'typename C' bằng' typename T' vì nó tạo ra sự nhầm lẫn cho người đọc (đã có một 'lớp C'). Cả hai trong mã ví dụ và câu trả lời của bạn. BTW, sự hiểu biết SFINAE của bạn khá tốt và thay vì tạo các mã độc lập như trên, bạn nên tạo một thư viện như mã sử dụng macro. Cũng lưu ý rằng, nó có thể không hoạt động đối với các biến 'private'. – iammilind

+0

@iammilind Cảm ơn, tôi đã cập nhật câu trả lời và mã ideone. – Holt

+0

Cách mới để tạo thành viên chung là tốt. Nhưng hãy tưởng tượng rằng, nó sẽ kết thúc việc tạo ra rất nhiều 'is_member _ ## MEM' do tính độc quyền của nó. Do đó bạn nên suy nghĩ về một cách, nơi bạn có thể đóng gói trong một lớp học và tiếp tục sử dụng cùng một. Về mặt kỹ thuật không có gì sai, ngay cả khi bạn tạo ra rất nhiều mẫu như vậy. Nhưng, đơn giản là không cần phải làm như vậy. Lợi thế phụ của 'lớp' là, bạn có thể có' giá trị bool', có thể được sử dụng cho mục đích in/kiểm tra. – iammilind

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