C++ templates working with objects *and* pointers

I want to make a function template that will work with object instances and pointers as well.
This is important to me as this is the first step towards implementing a function that operates on a vector of elements as well as a vector of pointers to elements.

Here my code so far


#include <functional>
#include <iostream>

struct Foo
{
    int num_ = 42;
    void print_num() const { std::cout << num_ << std::endl; }
};


template<typename T> void print_num(const T & obj)
{
    std::invoke(&T::print_num, obj);
}

template<typename T> void print_num_ptr(const T * const obj)
{
    std::invoke(&T::print_num, obj);
}


int main(int argc, char * argv[])
{
    Foo foo;
    Foo * foo_ptr = &foo;

    print_num(foo); // works
    print_num_ptr(foo_ptr); // works
    print_num(foo_ptr); // doesn't compile

    return 0;
}

And this is the compilation error I get

foo.cpp:14:18: error: type 'Foo *' cannot be used prior to '::' because it has no members
    std::invoke(&T::print_num, obj);
                 ^
foo.cpp:30:5: note: in instantiation of function template specialization 'print_num<Foo *>' requested here
    print_num(foo_ptr); // doesn't work
    ^
1 error generated.
make[2]: *** [CMakeFiles/foo.dir/foo.cpp.o] Error 1
make[1]: *** [CMakeFiles/foo.dir/all] Error 2
make: *** [all] Error 2

Any ideas?

Thanks.
Cheers

=========

❯❯  g++ --version
Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: x86_64-apple-darwin22.6.0
Thread model: posix

>Solution :

Remove the pointer-ness from the type using std::remove_pointer_t:

std::invoke(&std::remove_pointer_t<T>::print_num, obj);

If T isn’t a pointer, remove_pointer_t will return the same type unchanged.

Or, if your only goal is to support Foo::print_num(), not ??::print_num() in general, you can just use &Foo::print_num.

Leave a Reply