gcc,我可以将offsetof()与指向成员的模板化指针一起使用吗? [英] gcc, can I use offsetof() with templated pointer to member?

查看:123
本文介绍了gcc,我可以将offsetof()与指向成员的模板化指针一起使用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码在这里: https://ideone.com/XnxAyw

我得到的编译器错误是:

The compiler error I get is:

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

使用 offsetof(type,'pointer to member'')可以使Visual Studio正常,但这是因为它松懈了吗?如果是这样,有谁知道一种符合标准的方式来将offsetof()与指向成员模板参数的指针一起使用?

Visual Studio is OK with using offsetof(type, 'pointer to member') but is that because it's lax? If so, does anyone know a standards compliant way to use offsetof() with a pointer to member template argument?

#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

这时完全陷入了困境,这是第二次尝试:

Totally stumped at this point, here's the 2nd attempt:

#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;
}

推荐答案

对,这很粗糙,但似乎可以在GCC和MSVC上使用:

Right, this is grotty but seems to work on GCC and 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;
}

这篇关于gcc,我可以将offsetof()与指向成员的模板化指针一起使用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆