How to determine function signature of a callable object? - c++

Is there a way in C++ to determine function signature of a callable object?
Consider following:
template< typename F >
void fun(F f)
{
// ...
}
Lets assume that fun is called only with callable "things".
Inside of fun I want to know what is the signature of function f. That should work with function pointers, references, wrappers, lambdas, binds, function objects (providing they have only one operator ()) and so on. I'm limited with Visual Studio 2010 SP 1 but am interested in standard solutions even if not working on that compiler.
(A function signature is Return_Type ([Arg1_Type [, Arg2_Type [, ... ] ] ]); same as given to std::function/boost::function.)
A partial solution of knowing at least the return value of f is of some value to. (I have tried std::result_of but couldn't get it to work in any case I tried.)

On C++0x compliant compilers, you can at least get the result type of f() by using decltype(f()). Visual C++ 2010 should support decltype, though I haven't checked it myself yet. As for getting the argument types, I'm not sure if there's a way that would work with function pointers.
Edit
Boost.Function seems to have it figured out, at least on some compilers (it doesn't work on old versions of VC++ or Borland C++ for instance). It can wrap function pointers and extract arguments for them. The solution seems quite complex however, and it involves defining multiple templates with Boost.PP. If you feel like trying to re-implement everything you can certainly try that, but I think you can also just use a dummy Boost.Function wrapper to make things easier, e.g. boost::function<decltype(f)>::second_argument_type to get the second argument type.

You may look at Boost Function Types:
http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/boost_functiontypes/introduction.html

While trying to solve this I came up with following partial solution:
#include <cstdlib>
#include <functional>
#include <iostream>
#include <typeinfo>
#include <boost/bind.hpp>
#include <boost/function.hpp>
template< typename T >
struct identity
{
typedef T type;
};
// ----------
// Function signature metafunction implementation
// Also handler for function object case
// ----------
template< typename T >
struct function_signature_impl
: function_signature_impl< decltype( &T::operator() ) >
{
};
// ----------
// Function signature specializations
// ----------
template< typename R >
struct function_signature_impl< R () >
: identity< R () >
{
};
template< typename R, typename A1 >
struct function_signature_impl< R ( A1 ) >
: identity< R ( A1 ) >
{
};
template< typename R, typename A1, typename A2 >
struct function_signature_impl< R ( A1, A2 ) >
: identity< R ( A1, A2 ) >
{
};
// ----------
// Function pointer specializations
// ----------
template< typename R >
struct function_signature_impl< R ( * )() >
: function_signature_impl< R () >
{
};
template< typename R, typename A1 >
struct function_signature_impl< R ( * )( A1 ) >
: function_signature_impl< R ( A1 ) >
{
};
// ----------
// Member function pointer specializations
// ----------
template< typename C, typename R >
struct function_signature_impl< R ( C::* )() >
: function_signature_impl< R () >
{
};
template< typename C, typename R, typename A1 >
struct function_signature_impl< R ( C::* )( A1 ) >
: function_signature_impl< R ( A1 ) >
{
};
template< typename C, typename R >
struct function_signature_impl< R ( C::* )() const >
: function_signature_impl< R () >
{
};
template< typename C, typename R, typename A1 >
struct function_signature_impl< R ( C::* )( A1 ) const >
: function_signature_impl< R ( A1 ) >
{
};
// ----------
// Function signature metafunction
// ----------
template< typename T >
struct function_signature
: function_signature_impl< T >
{
};
// ----------
// Tests
// ----------
template< typename F >
void test( F f )
{
typedef function_signature< F >::type signature_type;
std::cout << typeid( F ).name() << std::endl;
std::cout << '\t' << typeid( signature_type ).name() << std::endl;
std::cout << std::endl;
}
int foo( int )
{
return 0;
}
struct bar
{
int operator ()( int )
{
return 0;
}
};
struct cbar
{
int operator ()( int ) const
{
return 0;
}
};
struct abar1
{
int operator ()( int ) const
{
return 0;
}
int operator ()( int )
{
return 0;
}
};
struct abar2
{
int operator ()( int )
{
return 0;
}
int operator ()( double )
{
return 0;
}
};
struct mem
{
int f( int ) const
{
return 0;
}
};
int main()
{
test(
[]( int ) -> int { return 0; }
);
test(
foo
);
test(
&foo
);
test(
bar()
);
test(
cbar()
);
test(
std::function< int ( int ) >( &foo )
);
test(
boost::function< void ( int ) >( &foo )
);
/*
test(
std::bind( &mem::f, mem(), std::placeholders::_1 )
);
*/
/*
test(
boost::bind( &mem::f, mem(), _1 )
);
*/
/*
test(
abar1()
);
*/
/*
test(
abar2()
);
*/
return EXIT_SUCCESS;
}
(No code for checking agains inproper arguments was added.)
The idea is that function_signature< decltype( f ) >::type should be the signature of a call of f( ... ) where that "..." is the signature. This means in particular that pointer to member function is an invalid argument here (although the code does not check against this) since such pointer cannot be "called" directly.
At the end are tests which fail (in VS 2010). All due to operator () being overloaded. And this makes that code mostly useless as it will not work with the result of bind. But maybe it can be further developed.
Answer to André Bergner's query:
function_signature_impl never derives from itself. It is a type template which only means a loosely coupled family of actual types. But the actual types (even thou they belong to the same family) are distinct types.
The &T::operator() is a pointer to a call operator (operator()) of type T – obviously. Basically just a member function pointer (where the member function happens to be a call operator). While decltype of it is the type of that pointer. This might seem insignificant (especially that type_info::name of both shows the same) but for templates it does matter since one is a pointer while the other is a type (apparently).
This “case” is needed to cover for functors (types which objects are “callable”). Note that this unspecialized function_signature_impl is used only if the template argument T doesn’t match anything else among the listed “cases”.
I hope I got it right after that long time. Although I’m not sure if I ever truly and fully understood it. The code was a bit result of experimenting.

This answer was just given to me by SlashLife on freenode ##c++:
template <typename T, typename Signature>
struct signature_impl;
template <typename T, typename ReturnType, typename... Args>
struct signature_impl<T, ReturnType(T::*)(Args...)>
{
using type = ReturnType(Args...);
};
template <typename T>
using signature_t = signature_impl<T, decltype(&T::operator())>;
The caveats are that it only works if there is a unique operator() and it doesn't work for lambdas.

You can use std::is_invocable_r

Related

How to pass a member function which has variable arguments as template argument?

I want to write an adapter which can convert non static member functions to C-style function pointers. Here is what I got now(see the following code snippet), but the current solution is not general. I want to make int (T::*Func)(int) accept variable arguments.
Also it's necessary to make CObjectT::f and StoreVals::display have the same signature.
The final goal is Interfacing C++ member functions with C libraries.
class StoreVals
{
int val;
public:
int display(int k) { cout << k << endl; return 0; }
};
template<class T, int (T::*Func)(int)>
class CObjectT
{
public:
/*
* The signagure of 'f(...)' should change by the argument of template.
* They must be the same, but i don't know how to achieve this goal.
*/
static int f(int i)
{
T obj;
return (obj.*Func)(i);
}
};
void main()
{
CObjectT<StoreVals, &StoreVals::display>::f(7);
auto function_t = &CObjectT<StoreVals, &StoreVals::display>::f;
// Now it's a C-style function pointer
cout << typeid(function_t).name() << endl;
}
I don't think it is possible to dynamically change the name of a function based on a template parameter, but you can change the arguments/return type based on the template parameter. It does require some extra type information in the template declaration but it does allow what you want.
#include <iostream>
#include <utility>
template< typename T, T t >
class Delegate;
template< typename R, typename C, typename... Args, R ( C::*F ) ( Args... )>
class Delegate< R ( C::*)( Args... ), F > {
public:
template< typename... Ts >
static R invoke( Ts&&... args ) {
C t;
return ( t.*F )( std::forward< Ts >( args )... );
}
};
template< typename R, typename... Args, R ( *F ) ( Args... ) >
class Delegate< R ( * ) ( Args... ), F > {
public:
template< typename... Ts >
static R invoke( Ts&&... args ) {
return F( std::forward< Ts >( args )... );
}
};
void print( int v ) {
std::cout << "Static: " << v << std::endl;
}
class Class {
void print( int v ) {
std::cout << "Class: " << v << std::endl;
}
};
int main( int argc, char** argv ) {
Delegate< void ( * )( int ), &print >::invoke( 1 );
Delegate< void ( Class::* ) ( int ), &Class::print >::invoke( 1 );
return 0;
}
Output:
Static: 1
Class: 1
This does use C++11's variadic templates and Rvalue References for perfect forwarding. That is why you see the weird std::forward< Args >( args )... in the function calls.
This doesn't work with variadic parameter functions such as printf and the like. It might be possible but would require a lot more template black magic that I don't have time to write and test.
If you want to interface with C, you cannot use templates and you cannot use member functions (even static). The only way is a honest hand-written extern "C" function. Templates or member functions cannot have C linkage.
If you want to sacrifice portability for convenience you can do something like this:
#define TYPE_AND_VALUE(x) decltype(x),x
#define MemFuncTypeAdapter(x) MemFuncTypeAdapterStruct<TYPE_AND_VALUE(x)>
extern "C"
{
int (*cfunc)(struct A*, int);
}
template <typename MemFuncType> struct MemFuncTypes;
template <typename Class, typename Ret, typename... Args>
struct MemFuncTypes<Ret (Class::*)(Args...)>
{
using RetType = Ret;
using ClassType = Class;
};
template <typename MemFuncType, MemFuncType memFunc>
struct MemFuncTypeAdapterStruct
{
using RetType = typename MemFuncTypes<MemFuncType>::RetType;
using ClassType = typename MemFuncTypes<MemFuncType>::ClassType;
template <typename... Args>
static RetType func (ClassType* c, Args... args)
{
return (c->*memFunc)(args...);
}
};
struct A
{
A() : a(33) {};
int a;
int plus (int b) { return a + b; }
};
int main ()
{
MemFuncTypeAdapter(&A::plus) aplus;
A a;
aplus.func(&a, 22);
cfunc = &MemFuncTypeAdapter(&A::plus)::func; //<- C interface here
}
Notes.
The adapter has an additional Class* argument. See comments for an explanation of this.
Don't bother with perfect forwarding. You are passing C compatible types in there anyway. Which means scalars and pointers only.
The ugly macro is necessary to avoid repeating typename(x), x every time. Hopefully a future C++ standard will deal with it.
Parts of this can probably be found in the standard library, pointers are welcome.
Demo

Accept any kind of callable and also know argument type

I'm not sure if it's possible, so that's what I want to find out.
I'd like to create a function which accepts any kind of functor/callable object, but I want to know what the argument type is. ( but not enforce it )
So, this one captures all but doesn't give me the type of the argument:
template < typename T >
void optionA( T );
This one captures most, and has the type of the argument
template < typename T >
void optionB( std::function< void(T) > );
But this one doesn't allow lambdas, so
optionB( [](int){} );
will not compile.
Which is somewhat strange, as this will compile:
std::function< void(int) > func = [](int){};
optionB( func );
So is there a way to accept all options and also know which type of argument is expected?
thanks in advance!
-- edit --
The reason I'd like to do this comes from the fact that I want the user of my library to register a callback with a certain type. To me, the most natural way is
auto callback = []( int val ) { cout << "my callback " << val << endl; };
object.register( callback );
(with or without the use of callback as intermediate variable)
Since I need to modify the behaviour based on the type of value the user expects, I need to know what type he/she expects.
Here's an example that will work for most callables including functors and lambdas (although not for generic functors as #Yakk demonstrated in a comment on the question).
The code can also be useful when determining return type and multiple arguments.
template <typename T>
struct func_traits : public func_traits<decltype(&T::operator())> {};
template <typename C, typename Ret, typename... Args>
struct func_traits<Ret(C::*)(Args...) const> {
using result_type = Ret;
template <std::size_t i>
struct arg {
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
template <typename T>
void option(T&& t) {
using traits = func_traits<typename std::decay<T>::type>;
using return_t = typename traits::result_type; // Return type.
using arg0_t = typename traits::template arg<0>::type; // First arg type.
// Output types.
std::cout << "Return type: " << typeid(return_t).name() << std::endl;
std::cout << "Argument type: " << typeid(arg0_t).name() << std::endl;
}
To add support for regular functions add a specialization e.g.
template <typename Ret, typename... Args>
struct func_traits<Ret(*)(Args...)> { /* ... */ }
More useful info: Is it possible to figure out the parameter type and return type of a lambda?
template < typename T >
void option( function< void(T) > )
{
cout << typeid( T ).name() << endl;
}
template < typename T >
void option( void (*func)(T) )
{
option( function< void(T) >( func ) );
}
template< typename F, typename A >
void wrapper( F &f, void ( F::*func )( A ) const )
{
option( function< void(A) >( bind( func, f, placeholders::_1 ) ) );
}
template< typename F, typename A >
void wrapper( F &f, void ( F::*func )( A ) )
{
option( function< void(A) >( bind( func, f, placeholders::_1 ) ) );
}
template < typename T >
void option( T t )
{
wrapper( t, &T::operator() );
}
void test( int )
{
}
struct Object
{
void operator ()( float )
{
}
};
int main( int, char *[] )
{
Object obj;
option( test );
option( [](double){} );
option( obj );
return 0;
}
Based on information found here c++0x: overloading on lambda arity, which I found through #dyps link
This isn't the best solution, since it requires overloads for const/non-const/volatile etc.
It does get the job done in terms of the original problem I was trying to solve...

Indexing using variadic templates

Let's say that I have a parameter pack I'm unrolling, e.g.
template<typename... P> void f(P...&& args) {
some_other_func(std::forward<P>(args)...);
}
Now let's say that I have some other minor function that these objects need to go through.
template<typename T> T&& some_func(T&& ref) {
// replace with actual logic
return std::forward<T>(ref);
}
I would normally just replace with
template<typename... P> void f(P...&& args) {
some_other_func(some_func(args)...);
}
But what do I do if some_func requires more information about the parameter than just it's type, like for example, it's position numerically in the parameter pack? So that instead of expanding to
some_other_func(some_func(arg1), some_func(arg2));
I could mke it expand to
some_other_func(some_func(arg1, 1), some_func(arg2, 2));
for example?
I know I've solved this before but can't recall how. Oh well, here's a fresh look.
The sequence of numbers can be translated into the argument sequence using std::get, so it is more fundamental. So, assuming that I need to implement some kind of custom tool, a number pack generator seems like a good choice.
(Gah, this was incredibly tedious. I did peek at Howard's answer and learned about forward_as_tuple, but that function doesn't even exist yet on my compiler or ideone.com, so blah. There are a lot of things I still need to get straight, and this is certainly one of the worst functional languages ever invented.)
http://ideone.com/u5noV
#include <tuple>
// Generic pack array (metacontainer)
template< typename T, T ... seq > struct value_sequence {
// Append a value to the array (metafunction)
template< T val > struct append
{ typedef value_sequence< T, seq..., val > type; };
};
// Generate a sequential array (metafunction)
template< size_t N >
struct index_sequence {
typedef typename index_sequence< N - 1 >::type
::template append< N - 1 >::type type;
};
template<>
struct index_sequence< 0 >
{ typedef value_sequence< size_t > type; };
// Generate indexes up to size of given tuple (metafunction)
template< typename T >
struct index_tuple {
typedef typename index_sequence< std::tuple_size< T >::value
>::type type;
};
// The magic function: passes indexes, makes all the function calls
template< typename F, typename G,
typename T, size_t ... N >
void compose_with_indexes_helper( F f, G g, T args,
value_sequence< size_t, N ... > ) {
f( g( std::get< N >( args ), N ) ... );
}
template< typename F, typename G, typename ... T >
void compose_with_indexes( F f, G g, T && ... args ) {
typedef std::tuple< T && ... > tuple_t;
compose_with_indexes_helper
// forwarding seems broken on ideone.com/GCC 4.5.1, work around.
// ( f, g, std::forward_as_tuple( std::forward( args ) ... ) );
( f, g, tuple_t( args ... ), typename index_tuple< tuple_t >::type() );
}
It is a little convoluted. But here is a working prototype of your code using several private utilities of libc++, found in
<__tuple>, and <tuple>.
#include <iostream>
#include <tuple>
template<typename T>
int
some_func(T&& ref, size_t I)
{
std::cout << "ref = " << ref << ", I = " << I << '\n';
return 0;
}
template<typename... T, size_t ...Indx>
void
some_other_func(std::tuple<T...> ref, std::__tuple_indices<Indx...>) {
// replace with actual logic
std::__swallow(some_func(std::get<Indx>(ref), Indx)...);
}
template<typename... P>
void
f(P&&... args)
{
some_other_func(std::forward_as_tuple<P...>(std::forward<P>(args)...),
typename std::__make_tuple_indices<sizeof...(P)>::type());
}
int main()
{
f("zero", "one", "two", "three");
}
ref = zero, I = 0
ref = one, I = 1
ref = two, I = 2
ref = three, I = 3

Why cannot the following SFINAE test detect a template member function?

compiling with GCC i get always false from the following code. I believe this is a compiler bug, but someone may know better.
#include <iostream>
template< class T >
class has_apply {
typedef char yes[1];
typedef char no[2];
template< class U, U u >
struct binder {};
template< class U, unsigned n >
static yes& test( U*,
binder< void (U::*) ( const double& ),
&U::template apply< n >
>* = 0
);
template< class U, unsigned n >
static no& test( ... );
public:
static const bool result =
( sizeof( yes ) == sizeof( test< T, 0u >( (T*)(0) ) ) );
};
class A {
public:
template< unsigned n >
void apply( const double& );
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
return( 0 );
}
I can't claim to understand why, but I was able to make your code work by not taking U* and by pulling the declaration of the binder type out:
template< class T >
class has_apply {
public:
typedef char yes[1];
typedef char no[2];
template< class U, U u >
struct binder {};
typedef binder< void (T::*)(const double&), &T::template apply<0u> > b;
template < typename V, unsigned n >
struct declare
{
typedef binder< void (V::*)(const double&), &V::template apply<n> > type;
};
template< typename U, unsigned n >
static yes& test( typename declare<U,n>::type * );
template< class U, unsigned n >
static no& test( ... );
static const bool result =
( sizeof( yes ) == sizeof( test< T, 0u >( 0 ) ) );
};
You can actually simplify this a bit by removing the unsigned parameter from the function and just sticking 0u in the typedef within 'declare'.
Again, I can't explain why this intermediate metafunction is necessary but it was required and the above works in MSVC++ 2010
Andy Venikov's answer over in [comp.lang.c++.moderated] (I'm only taking credit for great google-foo (he he, I cheated)):
http://groups.google.com/group/comp.lang.c++.moderated/msg/93017cf706e08c9e
Like Noah I don't know why. Unlike Noah I didn't find a workable solution, but investigating the thing I managed to crash the MingW g++ 4.4.1 compiler (that is, an Internal Compiler Error). This was simply by inconsistently referring to apply as template and non-template:
#include <iostream>
template< class T >
class has_apply {
template< class U, U u >
struct binder {};
template< class U >
static double test(
U*,
binder<
void (U::*) ( const double& ),
//&U::template apply< 0 >
&U::apply
>* = 0
);
public:
static binder<
void (T::*) ( const double& ),
&T::template apply< 0 >
>* dummy();
static const bool result = sizeof( test( (T*)(0), dummy() ) );
};
class A {
public:
// template< unsigned n >
void apply( const double& );
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
return( 0 );
}
Effect on g++:
C:\test> g++ -std=c++98 y.cpp
y.cpp: In instantiation of 'has_apply':
y.cpp:38: instantiated from here
y.cpp:24: internal compiler error: in instantiate_type, at cp/class.c:6303
Please submit a full bug report,
with preprocessed source if appropriate.
See for instructions.
C:\test> _
He he...
PS: I'd love to post this as a "comment", since it's not an "answer".
This is not an answer to why it doesn't work. However, researching through the web, I've found some examples and eventually got to the following code, which may be even more to the point then what I've been trying.
I was trying to detect an specific member function signature, but the code below goes beyond and detects whether a given call is possible, no matter what is the signature. Hope the comments will be helpful.
#include <iostream>
template< class T >
class has_apply {
class yes { char c; };
class no { yes c[2]; };
struct mixin {
void apply( void );
};
// Calling derived::apply is only non-ambiguous if
// T::apply does not exist, cf. 10.2.2.
template< class U> struct derived : public U, public mixin {};
// The following template will help on deduction based on this fact.
// If U is type void (mixin::*) (void) then the template can be
// instantiated with u = &derived< U >::apply if and only if T::apply
// does not exist.
template< class U, U u >
class binder {};
// Therefore, the following template function is only selected if there
// is no T::apply:
template< class U >
static no deduce( U, binder< void (mixin::*) (void), &derived< U >::apply >* = 0 );
// Selected otherwise.
static yes deduce( ... );
// Provides an T object:
static T T_obj( void );
public:
static const bool result = ( sizeof( yes ) == sizeof( deduce( T_obj() ) ) );
};
namespace aux {
// Class to represent the void type as a "true" type.
class void_type {};
// deduce() some lines below will give us the right answer based on
// the return type of T::apply<>, but if it is void we cannot use a
// call to T::apply as an argument to deduce. In fact, the only
// function in c++ that can take such an argument is operator,() with
// its default behaviour and if an overload is not well formed it
// falls back to default.
template< class T >
T& operator,( const T&, void_type ) {};
// Copies the constness of T into U. This will be required in order
// to not get false positives when no const member is defined.
template< class T, class U >
struct copy_constness {
typedef U result;
};
template< class T, class U >
struct copy_constness< const T, U > {
typedef const U result;
};
}
template< class T >
class has_correct_apply{
class yes { char c; };
class no { yes c[2]; };
// We assume has_apply< T >::result is true so the following class
// is well declared. It is declared in a way such that a call to
// derived::apply< n >() is always possible. This will be necessary
// later.
struct derived : public T {
using T::apply; // possible iff has_apply< T >::result == true
// This template function will be selected if the function call
// we wish is otherwise invalid.
template< unsigned n >
static no apply( ... );
};
// const_correct_derived will have the same constness than T.
typedef typename aux::copy_constness< T, derived >::result const_correct_derived;
// Provides a const correct derived object.
static const_correct_derived derived_obj( void );
// Only possible call was derived::apply: call is impossible for signature:
static no deduce( no );
// Since te returned value of it will most likely be
// ignored in our code (void must be always [almost, see next]
// ignored anyway), we return yes from this:
static yes deduce( ... );
// As we noticed, an overload of operator,() may make an exact match necessary.
// If we want this we could simply have used "no" instead of "yes" above and:
// static no deduce( aux::void_type );
public:
static const bool result = ( sizeof( yes ) == sizeof( deduce(
( derived_obj().template apply< 0u >( 0.0 ), aux::void_type() )
) ) );
// Note: Inteestingly enough, GCC does not detect an private subclass default
// constructor and so const_correct_derived() could be used instead of
// having a function derived_obj(), but I do not know if this behavoiur is
// standard or not.
};
struct C {
template< unsigned n >
int apply( double, unsigned m = 10 ) const;
private:
C();
};
struct D {
template< unsigned n >
int apply( const double& );
private:
D();
};
struct E : public C {
};
struct Without{};
#include "mp.h"
int main()
{
std::cout << has_apply< E >::result << '\n';
std::cout << has_correct_apply< const E >::result << '\n';
std::cout << has_correct_apply< const D >::result << '\n';
std::cout << has_correct_apply< D >::result << '\n';
// E e;
return( 0 );
}

accumulate the sum of elements in map, using value

Say I have a
struct SMyStruct
{
int MULT;
int VAL;
};
std::map<std::string, SMyStuct*> _idToMyStructMap;
Now I want to calculate total of all SMyStuct, where total is defined as MULT1 *VAL1 + MULT2 *VAL2 for each elements in the idToMyStructMap.
Seems like accumulate function is a natural choice. Please suggest. thanks
No Boost please.... just an 'ld fashion stl
typedef std::map< std::string, SMyStruct* > string_to_struct_t;
int add_to_totals( int total, const string_to_struct_t::value_type& data )
{
return total + data.second->MULT * data.second->VAL;
}
const int total = std::accumulate(
_idToMyStructMap.begin(),
_idToMyStructMap.end(),
0,
add_to_totals );
A variation on the theme would be to define operator+ for your struct, and then just use std::accumulate in its default mode.
int & operator+ (const int &lhs, const SMyStruct &rhs){
return lhs + (rhs.MULT * rhs.VALUE);
}
Then:
std::accumulate(_idToMyStructMap.begin(), _idToMyStructMap.end(), 0);
Of course, if operator+ makes sense in general for your struct, then you'd want to add overloads for using SMyStruct on the left as well, and/or make them templates so that you get functions for int, float, double, long, etc. all in one shot. As jalf mentioned in comments, if operator+ (or this version of it) doesn't make sense in general for your struct, then the other solution is better.
You can also separate the 'take second of pair' functionality from 'calculate MULT*VAL' and 'add something to an accumulator'.
Though you don't need boost to do this, they already created a great deal of a 'functional' programming framework. If you can't use boost, you need some template magic of your own. Not too complicated, though.
#include <map>
#include <algorithm>
#include <numeric>
#include <functional>
#include <iostream>
Now I deem it better to put the multiplication inside the class.
struct SMyStruct
{
int MULT;
int VAL;
long f() const { return MULT*VAL; }
};
Create a generic functor for 'take second of pair':
// a 'take-second' functor
template< typename at_pair >
struct to_second_t : public std::unary_function< at_pair, typename at_pair::second_type > {
const typename at_pair::second_type& operator()( const at_pair & p ) const {
return p.second;
}
};
This looks tricky, but is merely a generic way of saying: 'first do this, then do that with the result':
// compose two functors (simplified)
template< typename at_F, typename at_G >
struct compose_t : public std::unary_function< typename at_F::argument_type, typename at_G::result_type >{
at_F f;
at_G g;
compose_t( at_F& f, at_G& g ): f( f ), g(g) {}
typename at_G::result_type operator()( const typename at_F::argument_type& v ) const {
return g( f( v ) );
}
};
template< typename at_F, typename at_G >
compose_t<at_F, at_G> compose( at_F& f, at_G& g ) { return compose_t<at_F,at_G>( f, g ); }
// compose two functors (a unary one, and a binary one)
//
template< typename at_F, typename at_G >
struct compose2_t : public std::binary_function< typename at_F::first_argument_type, typename at_G::argument_type, typename at_G::result_type >{
at_F f;
at_G g;
compose2_t( at_F& f, at_G& g ): f( f ), g(g) {}
typename at_G::result_type operator()( const typename at_F::first_argument_type& a1, const typename at_G::argument_type& v ) const {
return f( a1, g( v ) );
}
};
template< typename at_F, typename at_G >
compose2_t<at_F, at_G> compose2( at_F& f, at_G& g ) { return compose2_t<at_F,at_G>( f, g ); }
And finally, putting it all in practice:
int main()
{
typedef std::map<int, SMyStruct > tMap;
tMap m;
SMyStruct s = {1,2};
m[1].VAL = 1; m[1].MULT = 3;
m[2].VAL = 2; m[2].MULT = 10;
m[3].VAL = 3; m[3].MULT = 2;
// mind, this is not LISP (yet)
long total = std::accumulate( m.begin(), m.end(), 0,
compose2(
std::plus<int>(),
compose(
to_second_t<tMap::value_type>(),
std::mem_fun_ref( &SMyStruct::f ) ) )
);
std::cout << "total: " << total <<std::endl;
return 0;
}