2014-03-12 103 views
1

下面的代碼是在這裏:https://ideone.com/XnxAywgcc,我可以使用帶模板指針的offsetof()成員嗎?

編譯器的錯誤,我得到的是:

prog.cpp: In member function ‘size_t list_base<T, NODE, true>::offset()’: 
prog.cpp:26:22: error: expected unqualified-id before ‘*’ token 
return offsetof(T, *NODE); 
       ^
prog.cpp:26:22: error: expected ‘)’ before ‘*’ token 

Visual Studio是使用offsetof(類型,「成員指針」)確定的,但就是因爲它是鬆懈?如果是這樣,有沒有人知道符合標準的方式使用offsetof()與指向成員模板參數的指針?

#include <stdio.h> 
#include <stddef.h> 

template <typename T> 
struct list_node_base 
{ 
    T *next; 
    T *prev; 
}; 

template <typename T> 
struct linked_list_node 
{ 
    list_node_base<T> list_node; 
}; 

template <typename T, linked_list_node<T> T::*NODE, bool is_member> 
struct list_base 
{ 
}; 

template <typename T, linked_list_node<T> T::*NODE> 
struct list_base<T, NODE, true> : linked_list_node<T> 
{ 
    size_t offset() 
    { 
     return offsetof(T, *NODE); 
    } 
}; 

template <typename T, linked_list_node<T> T::*NODE> 
struct list_base<T, NODE, false> : linked_list_node<T> 
{ 
    size_t offset() 
    { 
     return offsetof(T, decltype(*this)::list_node); 
    } 
}; 

template <typename T, linked_list_node<T> T::*NODE = nullptr> 
struct linked_list : list_base<T, NODE, (linked_list_node<T> T::*)nullptr != NODE> 
{ 
}; 

struct foo : linked_list_node<foo> 
{ 
}; 

struct bar 
{ 
    linked_list_node<bar> node; 
}; 

linked_list<foo> foo_list; 
linked_list<bar, &bar::node> bar_list; 

int main(int, char **) 
{ 
    return 0; 
} 

這裏的另一個嘗試:https://ideone.com/HD8PI0

在這一點上完全難住了,這裏的第2次嘗試:

#include <stdio.h> 
#include <stddef.h> 

template <typename T> struct list_node_base 
{ 
    T *next; 
    T *prev; 
}; 

template <typename T> 
struct linked_list_node 
{ 
    list_node_base<T> list_node; 
}; 

template <typename T, linked_list_node<T> T::*NODE, bool is_member> 
struct list_base 
{ 

}; 

template <typename T, typename R, R T::*M> 
size_t offset_of() 
{ 
    return reinterpret_cast<size_t>(&(((T*)0)->*M)); 
} 

template <typename T, typename M> M get_member_type(M T::*); 
template <typename T, typename M> T get_class_type(M T::*); 

#define OFFSET_OF(m) offset_of<decltype(get_class_type(m)), decltype(get_member_type(m)), m>() 

template <typename T, linked_list_node<T> T::*NODE> 
struct list_base<T, NODE, true> : linked_list_node<T> 
{ 
    size_t offset() 
    { 
     return OFFSET_OF(&T::*NODE); 
    } 
}; 

template <typename T, linked_list_node<T> T::*NODE> 
struct list_base<T, NODE, false> : linked_list_node<T> 
{ 
    size_t offset() 
    { 
     return OFFSET_OF(&T::list_node); 
    } 
}; 

template <typename T, linked_list_node<T> T::*NODE = nullptr> 
struct linked_list : list_base<T, NODE, (linked_list_node<T> T::*)nullptr != NODE> 
//struct linked_list : list_base<T, NODE, NODE> 
{ 
}; 

struct foo : linked_list_node<foo> 
{ 
}; 

struct bar 
{ 
    linked_list_node<bar> node; 
}; 

linked_list<foo> foo_list; 
linked_list<bar, &bar::node> bar_list; 

int main(int, char **) 
{ 
    return 0; 
} 

回答

0

沒錯,這是難看,但似乎對GCC和MSVC工作:

#include <stdio.h> 
#include <cstddef> 

////////////////////////////////////////////////////////////////////// 
// base list node class, 2 pointers 

template <typename T> 
class list_node_base 
{ 
public: 
    T *next; 
    T *prev; 
}; 

////////////////////////////////////////////////////////////////////// 
// base node is wrapped so we can get the offset to it 

template <typename T> 
class linked_list_node 
{ 
public: 
    list_node_base<T> list_node; 
}; 

////////////////////////////////////////////////////////////////////// 
// template base 

template <typename T, linked_list_node<T> T::*NODE, bool is_member> 
class list_base 
{ 
}; 

////////////////////////////////////////////////////////////////////// 
// specialization for instances using linked_list_node as member field 

template <typename T, linked_list_node<T> T::*NODE> 
class list_base<T, NODE, true> 
    : protected linked_list_node<T> 
{ 
protected: 
    static size_t offset() 
    { 
     linked_list_node<T> *b = &(((T *)0)->*NODE); 
     return size_t(&b->list_node); 
    } 
}; 

////////////////////////////////////////////////////////////////////// 
// specialization for instances deriving from linked_list_node 

template <typename T, linked_list_node<T> T::*NODE> 
class list_base<T, NODE, false> 
    : protected linked_list_node<T> 
{ 
protected: 
    static size_t offset() 
    { 
     list_node_base<T> T::*n = static_cast<list_node_base<T> T::*>(&T::list_node); 
     return (size_t)(&(((T *)0)->*n)); 
    } 
}; 

template <typename T, linked_list_node<T> T::*NODE = nullptr> 
#if defined(_MSC_VER) 
struct linked_list : list_base<T, NODE, NODE> 
#elif defined(__GNUC__) 
struct linked_list : list_base<T, NODE, (linked_list_node<T> T::*)nullptr != NODE> 
#endif 
{ 
}; 

struct foo : linked_list_node<foo> 
{ 
}; 

struct bar 
{ 
    int pad; 
    linked_list_node<bar> node; 
}; 

linked_list<foo> foo_list; 
linked_list<bar, &bar::node> bar_list; 

int main(int, char **) 
{ 
    printf("%d\n", bar_list.offset()); 
    printf("%d\n", foo_list.offset()); 
    getchar(); 
    return 0; 
} 
相關問題