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)
?
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
}
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
}