mgoldman mgoldman - 3 days ago 5
C++ Question

Using decltype with macro for explicit instantiation of class member functions

I am attempting to extend upon Can I use decltype (or something similar) for explicit template instantiation without signature duplication? for use with templated member functions, but I am having no luck. Current attempts at making this work look like:

// header
struct my_class
{
template <typename T>
some_type my_func(T val);
};

//source
template <typename T>
some_type my_class::my_func(T val)
{
....
}

// attempt a
template decltype(my_class::my_func<int>) my_class::my_func<int>;

// attempt b
template std::remove_pointer<decltype(&my_class::my_func<int>)>::type my_class::my_func<int>;


Is this possible? If so, any thoughts on how I can make this work?

EDIT:

so it appears that this requires some compiler update only available in clang or gcc 6.1+. The following code provided by @yakk will work for const methods:

template <class T>
struct pointer_to_member_function{};

template <typename pmf_t>
using pointer_to_member_signature
= typename pointer_to_member_function<pmf_t>::signature;

template <class ret_t, class class_t, class...args>
struct pointer_to_member_function<ret_t(class_t::*)(args...) const>
{
using signature = ret_t(args...) const;
};


However, the following modification does compile across all const-ness:

template <class function_t, class class_t>
struct pointer_to_member_function<function_t class_t::*>
{
using signature = function_t;
};

Answer

I do not know if this is standard compliant, but it works in clang:

template<class Pmf>
struct pmf_sig{};
template<class Pmf>
using pmf_sig_t=typename pmf_sig<Pmf>::type;
template<class R, class T, class...Args>
struct pmf_sig<R(T::*)(Args...)>{
  using type=R(Args...);
};

then const and const& and && support:

template<class R, class T, class...Args>
struct pmf_sig<R(T::*)(Args...) const>{
  using type=R(Args...) const;
};
template<class R, class T, class...Args>
struct pmf_sig<R(T::*)(Args...) const&>{
  using type=R(Args...) const&;
};
template<class R, class T, class...Args>
struct pmf_sig<R(T::*)(Args...) const&&>{
  using type=R(Args...) const&&;
};
template<class R, class T, class...Args>
struct pmf_sig<R(T::*)(Args...) &&>{
  using type=R(Args...) &&;
};
template<class R, class T, class...Args>
struct pmf_sig<R(T::*)(Args...) &>{
  using type=R(Args...) &;
};

The use:

template<> pmf_sig_t<decltype(&my_class::my_func<int>)> my_class::my_func<int>;

Or:

template pmf_sig_t<decltype(&my_class::my_func<int>)> my_class::my_func<int>;

The idea is that my_class:: is not part of the signature in some sense.

live example.

Comments