Pointer to member: works in GCC but not in VS2015

你离开我真会死。 提交于 2019-12-03 10:38:06

My preferred workaround is just to replace the properties member data with a properties member function:

class User
{
public:
    int age;

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

This works because in the definition of a member function, the class is considered to be completely defined. It also has the desirable attribute that properties doesn't need to be separately defined if odr-used.

MSVC doesn't know enough about User when it wants to calculate the type of properties to know it has a member age.

We can work around the problem.

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")
  );
}

In the JSON reflection code, simply replace std::decay_t<T>::properties with get_properties( tag<std::decay_t<T>> ).

This has a few advantages. First you can retrofit some classes you do not own or wish to modify with properties seamlessly. With careful namespace use and ADL enabling the point of call, you can even do so for (some) types within std (with oublic members only; pair at the least).

Second it avoids possible ODR-use requirements on properties. Properties is now a constexpr return value not some global data that may require storage.

Third it permits properties to be written out-of-line with the class definition like above, or inline as a friend within the class, for maximium flexibility.

If it is absolutely needed to properties be defined in User class maybe you could make use of helper templated constexpr function like:

#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()
{
}

It seems to compile in webcompiler i.e. VC++ 19.00.23720.0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!