How to get the type of non-static method without instance?

Viewed 125

I am trying to create a template function in C++ like:

template<typename IteratorType>
double evaluate(const IteratorType &rBegin, const IteratorType &rEnd,
    double(*function)( const decltype( *IteratorType ) &rObject )) // error, typename not allowed
    // I'm unsure if I need to put the reference there, not part of the problem.
{
    // ...
} 
// not my actual code, just to show an example.

Though this does not work since I need an instance of a class/struct to call a non-static method, which I can't do since it's in a function. After googling around a bit I found this solution:


double(*function)( const typename std::iterator_traits<IteratorType>::value_type &rObject )

Though as you can see this gets clumsy to use (and is a pain to change), especially when you are trying to create multiple overloads. This also did not seem to work for my iterators, so after a while I realized this:

double(*function)( const typename IteratorType::value_type &rObject)

would be the best solution.

In the end I realized there was no guarantee for "IteratorType" to have value_type defined as the type of the value, and that pointers are a thing.

Is there any way for me to get away with something along the lines of

double(*function)( const decltype(*IteratorType) &robject)

?

2 Answers

Though as you can see this gets clumsy to use [...]

Provide some template aliases and you could reduce the clumsiness!

template<typename IteratorType>
using ValueType = typename std::iterator_traits<IteratorType>::value_type;

template<typename IteratorType>
using FunctionPtr = double(*)(const ValueType<IteratorType> &);

template<typename IteratorType>
double evaluate(const IteratorType rBegin, const IteratorType rEnd,
    FunctionPtr<IteratorType> function)  // now you can simply this
{
    
}

First of all you need a minimal example to your problem. Here is what I understood from your comments:

#include <iostream>
#include <vector>
#include <string>

struct MyClass /* final */
{
    static double member(std::string const& val) /* noexcept */
    {
        std::cout << "double MyClass::member(int val): " << val << "\n";
        return {}; // return appropriate results
    }
};

template<typename IteratorType>
void evaluate(IteratorType rBegin, const IteratorType rEnd,
 // WHAT??? other than:
 // double(*function)(const typename std::iterator_traits<IteratorType>::value_type &rObject )
{
    while (rBegin != rEnd)
    {
        function(*rBegin);
        ++rBegin;
    }
}

int main()
{
    std::vector<std::string> vec{ "1", "2", "3"};
    evaluate(vec.cbegin(), vec.cend(), &MyClass::member);
}

Though as you can see this gets clumsy to use [...]

In addition to @Const's answer, if your problem is to use std::iterator_traits, you have following two other options.

  • Option - I

    Like @chtz mentioned in the comments, use std::declval to get the underline type of the iterators as follows:

    template<typename IteratorType>
    void evaluate(IteratorType rBegin, const IteratorType rEnd,
     double(*function)(
     std::remove_reference_t<decltype(*std::declval<IteratorType>())> const&))
     //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--> value_type == std::string 
    {
        // ... code 
    }
    
    

    Providing a helper template type alias wouldn't be a bad idea there:

    template<typename IteratorType>
    using ValueType = std::remove_reference_t<decltype(*std::declval<IteratorType>())>;
    
    template<typename IteratorType>
    void evaluate(IteratorType rBegin, const IteratorType rEnd,
       double(*function)(ValueType<IteratorType> const&))
       //                ^^^^^^^^^^^^^^^^^^^^^^^ value_type == std::string
    {
       // ... code
    }
    

    (See live demo)

  • Option - II

    From the rBegin, by converting the T& to T using std::remove_reference_t.

    
    template<typename IteratorType>
    void evaluate(IteratorType rBegin, const IteratorType rEnd,
       double(*function)(std::remove_reference_t<decltype(*rBegin)> const&))
       //                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---> std::string
    {
       // ... code
    }
    
    

    (See live demo)

Related