Is there pointer to member traits or something like this?

六月ゝ 毕业季﹏ 提交于 2019-12-09 13:17:41

问题


Based on other my question.

Consider the following code

template<typename T, int N>
struct A {
  typedef T value_type; // save T to value_type
  static const int size = N; // save N to size
};

Look, I can use value_type and size as template parameter.

typedef A<int, 2> A1;
typedef A<A1::value_type, A1::size + 3> A2;  // OK,  A2 is A<int,5>

Now I want to do the same with pointer to member:

struct Foo {
    int m;
    int r;
};

template<int Foo::*Mem>
struct B {
   static int Foo::* const mp;
};

template<int Foo::*Mem>
int Foo::* const B<Mem>::mp = Mem; // Save pointer to member

But I get error.

typedef B<&Foo::m> B1;
typedef B<B1::mp>  B2;  // DOES NOT WORK

How to make last line to work? Or how to get similiary result?

Note. I know that it does not work. No links to C++ Standard is needed. I need workaround.


回答1:


It shouldn't work according to C++ Standard 5.19/2:

Other expressions are considered constant-expressions only for the purpose of non-local static object initialization (3.6.2). Such constant expressions shall evaluate to one of the following:
— a null pointer value (4.10),
— a null member pointer value (4.11),
— an arithmetic constant expression,
— an address constant expression,
— a reference constant expression,
— an address constant expression for a complete object type, plus or minus an integral constant expression,
or
a pointer to member constant expression.

It is not the answer to the original question, but it is the answer to this wrong statement.




回答2:


Mike is right that it should compile. This is a bug in VS.




回答3:


Not totally an answer but do accessing Mem directly work?

ie: B1::Mem instead of B1::mp.

I'm pretty sure the standard do not allow it since we normally typedef template name when it's a type instead of accessing it directly, but technically it could maybe allow it (not sure what would be the implication). Where your solution is probably sure not to work since it require initialisation of a static member that is done at runtime (correct me if I'm wrong), so it cannot be accessed at compile time like you want to do.

Maybe you could try giving us the bigger picture of what you're trying to do with your trait/policy class to see if a suitable workaround is possible.




回答4:


I was surprised to find that there is not such thing. At least in the expected places, for example:

There is nothing here http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/index.html nor near here http://en.cppreference.com/w/cpp/types/is_member_pointer

Based on this http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html and this http://en.cppreference.com/w/cpp/types/is_member_pointer it is not hard to roll your own.

#include<type_traits> // std::is_pointer_member

template<class MP> struct member_pointer_traits_helper;

template< class T, class U >
struct member_pointer_traits_helper<T U::*>{
    using class_type = U;
    using declaration_type = T;
};

template< class MP >
struct member_pointer_traits : 
member_pointer_traits_helper<typename std::remove_cv<MP>::type> {};

struct B{
    int b;
};

int main(){
    using std::same;

    static_assert(std::is_member_pointer<int B::*>::value == true, "");
    static_assert(is_same<member_pointer_traits<int B::*>::class_type, B>{}, "");
    static_assert(is_same<member_pointer_traits<int B::*>::declaration_type, int>{}, "");
    static_assert(is_same<member_pointer_traits<decltype(&B::b)>::declaration_type, int>{}, "");
//  static_assert(is_same<member_pointer_traits<double>::class_type, B>{}, ""); // error
}

I am not sure if the names are optimal. Also when applied to non member pointer this will give a compiler error (this design is copied from http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html), another alternative could be to return the void type (which is obviously a failure return because void cannot be a class or a member type.)

(with some small modifications it can be used with C++98, used C++11 to make it more clear.)



来源:https://stackoverflow.com/questions/1914342/is-there-pointer-to-member-traits-or-something-like-this

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