The code below gives the following compilation error:
main.cpp:5:48: error: invalid use of non-static data member 'id'
static constexpr int Type::* mem_ptr_id = &id;
^~
main.cpp:5:34: error: default initialization of an object of const type 'int Type::*const'
static constexpr int Type::* mem_ptr_id = &id;
^
= nullptr
main.cpp:6:46: error: invalid use of non-static data member 'id'
static constexpr auto mem_ptr_id_auto = &id;
^~
main.cpp:6:27: error: declaration of variable 'mem_ptr_id_auto' with deduced type 'const auto' requires an initializer
static constexpr auto mem_ptr_id_auto = &id;
^
4 errors generated.
which is kind of expected.
#include <iostream>
struct Type {
int id;
static constexpr int Type::* mem_ptr_id = &id; // &Type::id required
static constexpr auto mem_ptr_id_auto = &id; // &Type::id required
};
int main() {
Type test;
test.*Type::mem_ptr_id = 5; // same as test.id = 5
test.*Type::mem_ptr_id_auto = 5; // same as test.id = 5
std::cout << test.id << std::endl; // expected: 5
return 0;
}
I need a way to have static pointer-to-member variable of my class/structure without explicitly naming the type (class/struct) name. Any suggestions?
Note:
In order to avoid auto
to become int&
, I did pointer-to-member wrapper:
template<typename T, class E>
struct Pointer2Member {
using var_t = T;
using entity_t = E;
using mem_ptr_t = T E::*;
T E::* data;
constexpr Pointer2Member() {}
constexpr Pointer2Member(T E::* val) : data(val) {}
constexpr operator T E::* () {
return data;
}
};
template<auto ptr>
struct Pointer2MemberOf;
template<typename T, class E, T E::* ptr>
struct Pointer2MemberOf<ptr> : Pointer2Member<T, E> {
constexpr Pointer2MemberOf() : Pointer2Member<T, E>(ptr) {}
constexpr operator Pointer2Member<T, E>() {
return *this;
}
};
struct Type {
int id;
static constexpr auto mem_ptr_id = Pointer2MemberOf<&id>(); // Pointer2MemberOf<&Type::id>() required
};
but it gives same error:
main.cpp:34:58: error: invalid use of non-static data member 'id'
static constexpr auto mem_ptr_id = Pointer2MemberOf<&id>();
^~
main.cpp:34:27: error: declaration of variable 'mem_ptr_id' with deduced type 'const auto' requires an initializer
static constexpr auto mem_ptr_id = Pointer2MemberOf<&id>();
^
main.cpp:40:17: error: no member named 'mem_ptr_id_auto' in 'Type'
test.*Type::mem_ptr_id_auto = 5; // same as test.id = 5
~~~~~~^
3 errors generated.
Note 2: Follow-up on the comment "What do you need this for":
Unfortunately, it is very complicated variadic template solution which I can't talk a lot about.
What I want to achieve is to create a template class Result<...>
which can store custom member variables of different classes.
Result<User::id, User::username, Post::id>
and Result<User, Post::id>
should both be viable syntaxes and should have Result<User, Post::id>::get<PROPERTY>
which should be able to have both Result<User, Post::id>::get<User>
and Result<User, Post::id>::get<User::id>
(yes, User
, not Post
).
Imagine Result<...>
class in a library that will be used by beginner C++ programmers so I don't want to use the &User::id
syntax as it might be too complicated to comprehend for them.
Also, the static member will be auto-generated via macros like
#define Member(TYPE, NAME) TYPE _##NAME; static constexpr auto NAME = Pointer2Member(&_##NAME)
struct User {
Member(int, id);
Member(std::string, username);
};
Result<User::id> result1;
result1.get<User::id>() = 5;
Result<User> result2;
result2.get<User::id>() = 6;
result2.get<User::username>() = "John";
Yes, but not in static. Generally you can replace the reference to class/struct name such as
Test
bystd::remove_reference_t<decltype(*this)>
, but only ifthis
is available.For example you can replace
decltype(&Test::somefunc)
bydecltype(&std::remove_reference_t<decltype(*this)>::somefunc)
, which can be useful in templates.If you modify your example to something like this, then it will also work:
As you can see none of those are static anymore (mem_ptr_id has default initialization), and access to
mem_ptr_id
is a bit awkward. But otherwise yes, it is possible in this way as long asthis
is available, and it can be very useful for templates/macros. Minimum C++14 required.Also just for fun I will paste an example code snippet where it can be useful in practice:
As we can see, in the macro above it would be quite annoying to have to pass
IVEngineClient
as one of the parameters manually every time. And this trick does well to avoid that.