15

I wanted to have type traits which will help me to get the type of the class from a member function pointer. I looked into this answer and found my half way to the aim.

It looks like this:

#include <iostream>

// example class
struct MyClass {
    void funct() { std::cout << "funct has been called....\n"; }
};

// traits
template<typename Class> struct get_class{};
template<typename ReType, typename Class, typename... Args>
struct get_class<ReType(Class::*)(Args...)>
{
    using type = Class;
};
template<typename Type> using get_class_t = typename get_class<Type>::type;

int main()
{
    get_class_t<decltype(&MyClass::funct)> myObj;
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---> this is a lot of typing
    myObj.funct();
    return 0;
}

But, as shown in the code I need every time to write get_class_t<decltype(&MyClass::funct)> or in the case of

  auto ptr =  &MyClass::funct;
  get_class_t<decltype(ptr)> myObj;
  //         ^^^^^^^^^^^^^^

which is a lot of decltype()ing. I would like to write instead

class_t<ptr> obj;
or
class_t<&MyClass::funct> myObj;

which is more convenient.

I did the following function, which will return a resulting object of the class and maybe I could do, want I wanted to.

template<typename Type>
auto helper_function(Type ptr)->get_class_t<Type>
{
    return get_class_t<Type>{};
}

template<typename Type>
using class_t = /* decltype(helper_function(Type ptr));*/ 
//             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // what could be here?

I do not know how to complete this. My goal is to extend the traits in such a way that I could create an object like

auto ptr = &MyClass::funct;
class_t<ptr> myObj;
// or
class_t<&MyClass::funct> myObj;

Is there any other way to do this? or should I have to stick with decltype()ing?

As I have tagged, I would like to see whether it possible with C++11?

Failed Scientist
  • 1,977
  • 3
  • 29
  • 48
UserUsing
  • 678
  • 1
  • 5
  • 16
  • 2
    As I tagged I would like to see whether it possible with **C++11**? – UserUsing May 13 '19 at 10:21
  • 5
    @Someprogrammerdude IMO if one tags the specific version of the standard that person want's an answer for that standard. I think it's always crucial – Timo May 13 '19 at 10:26
  • @Timo, the OP and others: Many beginners and newbies (and sometime intermediate knowledge posters) very often put specific standard-version tags in their question, when their questions could be about generic C++. It's impossible without explicit mentioning to know if it's deliberate or by mistake. – Some programmer dude May 13 '19 at 10:31
  • No, this is not really possible in C++11. – L. F. May 13 '19 at 10:47
  • 1
    @Someprogrammerdude Then err on the side of caution by asking first if you're not sure!! – Lightness Races in Orbit May 13 '19 at 10:59
  • Out of curiosity... what is the use case you envision? – bremen_matt May 13 '19 at 18:43

2 Answers2

11

(Answer archived for future visitors; this solution requires C++17!)


You're really close!

The trick is auto template arguments, and the fact that pointers-to-members can be used as template arguments, like so:

template <auto thing>
using class_t = get_class_t<decltype(thing)>;

int main()
{
    class_t<&MyClass::funct> myObj;
    myObj.funct();
}

Of course if you can write this then you already know the type so you'd just write MyClass, so that's not very useful.

Sadly you won't be able to make it accept ptr as a template argument, though; you're stuck with get_class_t for that:

int main()
{
    auto ptr = &MyClass::funct;
    get_class_t<decltype(ptr)> myObj;
    myObj.funct();
}

(live demo)

In the latter case, a nice type alias can help you a bit:

auto ptr = &MyClass::funct;

using ClassType = get_class_t<decltype(ptr)>;
ClassType myObj;

myObj.funct();

(live demo)

Personally I think this level of verbosity is pretty reasonable.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    I have already so that in the linked post. But `auto things` need C++17. As I tagged I would like to see whether it possible with **C++11**. https://godbolt.org/z/3v3SVh – UserUsing May 13 '19 at 10:20
  • 2
    @UsingCpp Dang, someone removed that tag. Sorry. I'll keep this answer up for posterity but I think you're out of luck then. – Lightness Races in Orbit May 13 '19 at 10:22
8

You can provide a function which will create required object. This is very simple to achieve:

template<typename T, typename ...Args>
auto makeObjectForMethod(T&&, Args&& ...args) -> get_class_t<decltype(&MyClass::funct)>
{
    using R = get_class_t<decltype(&MyClass::funct)>;
    return R{ std::forward(args)... };
}

int main()
{
    auto myObj = makeObjectForMethod(&MyClass::funct);

    myObj.funct();
    return 0;
}

Works with C++11 and is quite handy: https://wandbox.org/permlink/usMa3fA0I2HCNJ7M

The only disadvantage that in case of class fields it is not very helpful.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • A good solution iff there are no ctor args. Not a general solution but I suppose that may not matter here. – Lightness Races in Orbit May 13 '19 at 12:21
  • current version works with ctor args, which can be passed as extra arguments of `makeObjectForMethod`. – Marek R May 13 '19 at 12:56
  • Better! Still not sure I'd use this in reality but it's a valid workaround to not being able to get just the type. Just be careful of potential copies on return if the thingie isn't moveable (and RVO doesn't kick in) cos this is pre-C++17 – Lightness Races in Orbit May 13 '19 at 13:09
  • I realize there is no way out for C++11 compiler but this could make it better, but not the best. – UserUsing May 14 '19 at 07:00