I have the following type, which I get with decltype
QString UserInfo::*&
I can remove the &
part by wrapping decltype
with std::remove_reference_t
but I also want to remove UserInfo::*
part
How can I do that so I can use only QString
type in my templates
I'm using this template in initializer list where I don't have access to solid object or this pointer to .*
operator in decltype
CodePudding user response:
Using a valid object is not necessary in unevaluated contexts (like decltype
). To exaggerate a little, you could even dereference a null pointer in there, and nothing bad would happen, since the dereference is never actually evaluated.
To create an object of a type that is not valid, but can be used in unevaluated contexts, you can use std::declval
.
template<class T>
using member_type = decltype(std::declval<UserInfo>().*std::declval<T>());
CodePudding user response:
You can write a trait to extract the type of the member from the member function pointer:
#include <type_traits>
template <typename T>
struct member_type;
template <typename C, typename T>
struct member_type<T C::*> {
using type = T;
};
template <typename T>
using member_type_t = typename member_type<T>::type;
struct foo {
int bar;
};
int main()
{
int foo::*ptr = &foo::bar;
using T = member_type_t<decltype(ptr)>;
static_assert( std::is_same_v<int,T>);
}
CodePudding user response:
Use template specialization to extract member type:
template <typename MemberType>
struct member_type;
template <typename Class, typename Member>
struct member_type<Member Class::*>
{
using type = Member;
};
template<typename T>
using member_type_t = typename member_type<T>::type;
class A
{
public:
int b;
};
using t = member_type_t<decltype(&A::b)>;
CodePudding user response:
Here is my version using C 17 in such way that decltype
is not needed when template is used (a bit more handy):
#include <iostream>
#include <string>
#include <type_traits>
template <auto Fp>
struct field_type;
template<typename R, typename T, R (T::*FP)>
struct field_type<FP>
{
using type = R;
};
template<typename R, typename T, typename...Args, R (T::*FP)(Args...)>
struct field_type<FP>
{
using type = R;
};
template<auto FP>
using field_type_t = typename field_type<FP>::type;
class Foo {
public:
int x = 0;
double y = 0;
std::string s;
const int cx = 0;
Foo() = default;
void bar() {
std::cout << "bar\n";
}
int par(int z) {
std::cout << "bar\n";
return z;
}
};
template<auto F, typename T>
constexpr bool test = std::is_same_v<field_type_t<F>, T>;
static_assert(test<&Foo::x, int>, "");
static_assert(test<&Foo::cx, const int>, "");
static_assert(test<&Foo::s, std::string>, "");
static_assert(test<&Foo::y, double>, "");
#ifndef HIDE_PROBLEM_ON_GCC_11
static_assert(test<&Foo::bar, void>, "");
static_assert(test<&Foo::par, int>, "");
#endif
For some strange reason works on all compilers, but not for gcc 11.1 or newer.