指向成员的指针:适用于GCC,但不适用于VS2015 我试图实现一个“属性”系统,将C++实例转换成JSON,反之亦然。我从纪尧姆·拉西科特(Guillaume Racicot)在这个问题()中的回答中提取了部分代码,并对其进行了简化

指向成员的指针:适用于GCC,但不适用于VS2015 我试图实现一个“属性”系统,将C++实例转换成JSON,反之亦然。我从纪尧姆·拉西科特(Guillaume Racicot)在这个问题()中的回答中提取了部分代码,并对其进行了简化,c++,c++11,visual-c++,visual-studio-2015,c++14,C++,C++11,Visual C++,Visual Studio 2015,C++14,以下是我如何进行的。我有一个属性类: template <typename Class, typename T> struct Property { constexpr Property(T Class::* member, const char* name) : m_member(member), m_name(name) {} T Class::* m_member; const char* m_name; }; 此代码在GCC()中编译并正常工作,但

以下是我如何进行的。我有一个
属性
类:

template <typename Class, typename T>
struct Property {
    constexpr Property(T Class::* member, const char* name) : m_member(member), m_name(name) {}

    T Class::* m_member;
    const char* m_name;
};
此代码在GCC()中编译并正常工作,但在Visual Studio 2015 Update 3中不正确。我发现这些错误:

main.cpp(19) : error C2327 : 'User::age' : is not a type name, static, or enumerator
main.cpp(19) : error C2065 : 'age' : undeclared identifier
main.cpp(20) : error C2672 : 'std::make_tuple' : no matching overloaded function found
main.cpp(20) : error C2119 : 'properties' : the type for 'auto' cannot be deduced from an empty initializer

在Visual Studio 2015 Update 3中是否有一种变通方法可以使其正常工作?

如果绝对需要在用户类中定义属性,也许您可以使用帮助器模板的constepr函数,如:

#include <tuple>

template <typename Class, typename T>
struct Property {
    constexpr Property(T Class::* const member) : m_member{ member } {}

    T Class::* const m_member;
};

template <class T, class V>
constexpr Property<T, V> get_age_property() {
    return  Property<T, V>(&T::age);
}

class User
{
public:
    int age;

    constexpr static std::tuple<Property<User, int>> properties = std::make_tuple(
         get_age_property<User, int>()
    );

};

int main()
{
}
#包括
模板
结构属性{
constexpr属性(T类::*const成员):m_成员{member}{}
T类::*const m_成员;
};
模板
constexpr属性get\u age\u属性(){
返回属性(&T::年龄);
}
类用户
{
公众:
智力年龄;
constexpr static std::tuple properties=std::make\u tuple(
get_age_属性()
);
};
int main()
{
}

它似乎是在VC++19.00.23720.0中编译的当MSVC想要计算
属性的类型时,它对
用户
了解不够,从而知道它有一个成员
年龄

我们可以解决这个问题

template<class T>struct tag_t{constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag{};

template<class T>
using properties = decltype( get_properties( tag<T> ) );

class User
{
public:
  int age;

};
constexpr auto get_properties(tag_t<User>) {
  return std::make_tuple(
    Property<User, int>(&User::age, "age")
  );
}
templatestruct标签{constexpr标签{};};
templateconstexpr标签{};
模板
使用properties=decltype(get_properties(tag));
类用户
{
公众:
智力年龄;
};
constexpr自动获取属性(标记){
返回std::make_tuple(
属性(&用户::年龄,“年龄”)
);
}
在JSON反射代码中,只需将
std::decay\u t::properties
替换为
get\u properties(tag)

这有几个优点。首先,您可以使用属性无缝地修改一些您不拥有或不希望修改的类。通过小心地使用命名空间和启用调用点的ADL,您甚至可以对
std
中的(某些)类型执行此操作(仅限oublic成员;至少成对)

其次,它避免了对属性可能的ODR使用要求。属性现在是一个
constexpr
返回值,而不是一些可能需要存储的全局数据


第三,它允许写入与上述类定义不一致的属性,或在类中作为
友元
内联,以获得最大的灵活性。

我首选的解决方法是用
属性
成员函数替换
属性
成员数据:

class User
{
public:
    int age;

    constexpr static auto properties() { return std::make_tuple(
        Property<User, int>(&User::age, "age")
    ); }
};
类用户
{
公众:
智力年龄;
constexpr static auto properties(){return std::make_tuple(
属性(&用户::年龄,“年龄”)
); }
};

这是因为在成员函数的定义中,类被认为是完全定义的。它还有一个可取的属性,即如果使用odr,
属性
不需要单独定义。

属性
构造函数需要一个或两个参数吗?@pts是的,我把代码放在这里:完全相同的代码不会在VS2015(更新3)中编译。我认为MSVC在完全定义之前无法看到类内部(
User::age
在解析
};
之前是未知的)。至于MSVC或GCC是否正确,请阅读2个答案
class User
{
public:
    int age;

    constexpr static auto properties() { return std::make_tuple(
        Property<User, int>(&User::age, "age")
    ); }
};