以下代码位于:https://ideone.com/XnxAyw
我得到的编译错误是:
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(类型,&#39;指向成员&#39;的指针),但这是因为它的松懈?如果是这样,有没有人知道一种符合标准的方法来使用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
此时完全难过,这是第二次尝试:
#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 :(得分: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;
}