auto template parameter, data member and constness

86 views Asked by At

Suppose I have a pointer to data member and I want to know if it's const or not. In other words:

struct S {
    const int i; // this is const
    int j;
};

In C++ I used to do something like this:

template<typename Class, typename Type, Type Class:: *>
struct is_const_data_member: std::false_type {};

template<typename Class, typename Type, const Type Class:: *Member>
struct is_const_data_member<Class, const Type, Member>: std::true_type {};

template<typename Class, typename Type, Type Class:: *Member>
void foo() {
    const auto bar = is_const_data_member<Class, Type, Member>::value;
    // ...
}

However, now there is the auto template parameter and template parameters list are much elegant:

template<auto Member>
void foo() {
    // ...
}

In this case, the solo way I found to know if the data member point to something that is const is:

const auto bar = std::is_const_v<std::remove_reference_t<decltype(std::declval<Class>().*Member)>>;

However, it looks ugly to me and I feel like there must be a better way to do it.
Is there any other (shorter) solution for that?

2

There are 2 answers

0
Michael Kenzel On

How about something like this:

template <typename T>
struct is_const_data_member : std::false_type {};

template <typename C, typename T>
struct is_const_data_member<const T C::*> : std::true_type {};

template <auto T>
constexpr bool is_const_data_member_v = is_const_data_member<decltype(T)>::value;

And then, for example

struct Test
{
    int a;
    const int b;
};


bool x = is_const_data_member_v<&Test::a>;
bool y = is_const_data_member_v<&Test::b>;

working test here

0
HolyBlackCat On

You could change is_const_data_member to operate on a single type template parameter:

template<typename MemPtr>
struct is_const_data_member: std::false_type {};

template<typename Class, typename Type>
struct is_const_data_member<const Type Class::*>: std::true_type {};

Then, from template<typename Class, typename Type, Type Class:: *Member> void foo() you use it as

is_const_data_member<Type Class::*>::value

(Which, in my opinion, is slightly more intuitive.)

And from template<auto Member> void foo() you use it as

is_const_data_member<decltype(Member)>::value

You could also rewrite the trait to operate on an auto template parameter. But by using a type parameter you avoid unnecessary instantinations for different pointers of same type, which is supposedly a good thing.