How can I iterate over a tuple starting from, say, index 1 to 2? The following doesn't work.
using boost::fusion::cons;
typedef cons<A, cons<B, cons<C, cons<D> > > > MyTuple;
MyTuple tuple_;
template <class T>
struct DoSomething{
DoSomething(T& t) : t_(&t){ }
template <class U>
void operator()(U u){
boost::fusion::at<mpl::int_<u> >(*t_);
}
T* t_;
};
boost::mpl::for_each< boost::mpl::range_c<int, 1, 3> >( DoSomething<MyTuple>(tuple_) );
I'm not sure about your intent, but will the following code serve your purpose?
I used fusion all over instead of mpl.
struct DoSomething {
template< class U >
void operator()( U u ) const {
std::cout << u << '\n'; // an example
}
};
using namespace boost::fusion; // Sorry, for brevity
iterator_range<
result_of::advance_c< result_of::begin< MyTuple >::type, 1 >::type
, result_of::advance_c< result_of::begin< MyTuple >::type, 3 >::type
> ir( advance_c< 1 >( begin( tuple_ ) )
, advance_c< 3 >( begin( tuple_ ) ) );
for_each( ir, DoSomething() );
Hope this helps
Judging from your comment,
what you mentioned can be implemented probably by making a predicate
class which determines whether the specified class has the member function,
and using fusion::filter_view.
DEF_HAS_MEM_FUNC macro in the following code is explained at:
Is it possible to write a template to check for a function's existence?
#include <boost/fusion/include/cons.hpp>
#include <boost/fusion/include/filter_view.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/placeholders.hpp>
using namespace boost;
#define DEF_HAS_MEM_FUNC( name, func_name, signature ) \
template< class T > \
struct name { \
template< class U, U > struct mfp; \
\
template< class U > \
static char f( mfp< signature, &U::func_name >* ); \
\
template< class > static char (&f(...))[2]; \
\
enum { value = (sizeof( f<T>(0) ) == 1) }; \
}
DEF_HAS_MEM_FUNC( has_f, f, void(U::*)()const );
struct DoSomething {
template< class U >
void operator()( U& u ) const {
u.f();
}
};
struct A {};
struct B {
void f() const {}
};
typedef fusion::cons< A, fusion::cons< B > > MyTuple;
int main()
{
MyTuple tuple_;
fusion::filter_view< MyTuple const, has_f< mpl::_ > > v( tuple_ );
fusion::for_each( v, DoSomething() );
}
Related
I like using factory design pattern to inject dependencies, but that means having lots of very similar classes (almost one factory per class). Then I got to an idea to create a generic factory pattern using templates. Something like this:
// g++ -std=c++14 -Wall -Wextra factory.cpp -o factory
#include <functional>
#include <memory>
#include <utility>
#include <iostream>
template < typename T, typename Base = typename T::Iface >
class Factory
{
public:
template < typename... Args >
using CreatorFn = std::function< std::shared_ptr< Base > ( Args&&... ) >;
template < typename... Args >
static std::shared_ptr< Base > Create( Args&&... args );
template < typename... Args >
static void ResetToDefaultCreator();
template < typename... Args >
static void SetCreator( CreatorFn< Args... > fn );
private:
Factory() = delete;
template < typename... Args >
static CreatorFn< Args... >& Creator();
template < typename... Args >
static std::shared_ptr< Base > DefaultCreator( Args&&... args );
};
template < typename T, typename Base >
template < typename... Args >
std::shared_ptr< Base > Factory< T, Base >::Create( Args&&... args )
{
return Creator< Args... >()( std::forward< Args >( args )... );
}
template < typename T, typename Base >
template < typename... Args >
void Factory< T, Base >::ResetToDefaultCreator()
{
CreatorFn< Args... >() = DefaultCreator< Args... >;
}
template < typename T, typename Base >
template < typename... Args >
void Factory< T, Base >::SetCreator( CreatorFn< Args... > fn )
{
Creator< Args... >() = fn;
}
template < typename T, typename Base >
template < typename... Args >
Factory< T, Base >::CreatorFn< Args... >& Factory< T, Base >::Creator()
{
static CreatorFn< Args... > creator = DefaultCreator< Args... >;
return creator;
}
template < typename T, typename Base >
template < typename... Args >
std::shared_ptr< Base > Factory< T, Base >::DefaultCreator( Args&&... args )
{
return std::make_shared< T >( std::forward< Args >( args )... );
}
struct A {
virtual ~A() = default;
virtual void foo() = 0;
};
struct B : public A {
using Iface = A;
virtual void foo()
{
std::cout << "-- B::foo()" << std::endl;
}
};
struct C : public A {
using Iface = A;
C( int, float )
{
}
virtual void foo()
{
std::cout << "-- C::foo()" << std::endl;
}
};
struct D : public A {
using Iface = A;
D( int, float )
{
}
virtual void foo()
{
std::cout << "-- D::foo()" << std::endl;
}
};
using FactoryDefaultConstructor = Factory< B >;
using FactoryParamsConstructor = Factory< C >;
struct MyClass
{
MyClass() : a( FactoryParamsConstructor::Create( 3, 5.7f ) )
{}
void foo()
{
a->foo();
}
private:
std::shared_ptr< A > a;
};
int main()
{
FactoryParamsConstructor::ResetToDefaultCreator<int,float>();
std::shared_ptr< A > obj1 = FactoryParamsConstructor::Create( 3, 5 );
C* realObj1 = dynamic_cast< C* >( obj1.get() );
if ( nullptr != realObj1 )
{
std::cout << "1 created" << std::endl;
}
else
{
std::cout << "1 failed" << std::endl;
}
MyClass class1;
class1.foo();
FactoryParamsConstructor::CreatorFn< int, float > newCretorFn = []( int a,float b ){
std::cout << "****cb called"<<std::endl;
return std::shared_ptr< A >( new D( a, b ) );
};
FactoryParamsConstructor::SetCreator< int, float >( newCretorFn );
std::shared_ptr< A > obj2 = FactoryParamsConstructor::Create( 3, 5.7f );
D* realObj2 = dynamic_cast< D* >( obj2.get() );
if ( nullptr != realObj2 )
{
std::cout << "2 created" << std::endl;
}
else
{
std::cout << "2 failed" << std::endl;
}
float p = 5.5f;
std::shared_ptr< A > obj3 = FactoryParamsConstructor::Create( 3, p );
D* realObj3 = dynamic_cast< D* >( obj3.get() );
if ( nullptr != realObj3 )
{
std::cout << "3 created" << std::endl;
}
else
{
std::cout << "3 failed" << std::endl;
}
MyClass class2;
class2.foo();
}
Output:
1 created
-- C::foo()
****cb called
2 created
3 failed
****cb called
-- D::foo()
This works, but with certain problems:
if I don't take care what I pass to the Create() method, it can fail, since it is going to use wrong instance of the Creator() method. Is there a way to fix this? This is the reason why creation of obj3 fails.
The SetCreator() method can take only std::function objects. I understand why. My question is, can I change it to take anything appropriate and call correct Creator() method?
Ideally, it would have this declaration:
template < typename F >
static void SetCreator( F fn );
Then I could do this:
std::shared_ptr< A > foo( int, float ) { return new B; };
FactoryParamsConstructor::SetCreator( foo );
Maybe overloaded is what you want (C++17, but might be implemented for C++11):
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
const auto Afactory = overloaded {
[]() { return std::make_shared<B>(); },
[](int a, int b) { return std::make_shared<C>(a, b); },
[](int a, float b) { return std::make_shared<D>(a, b); },
};
Demo
I figured out how to do, and posting my solution.
template < typename T, typename Base = typename T::Iface >
class Factory
{
public:
using ReturnType = std::shared_ptr< Base >;
template < typename... Args >
using CreatorFn = std::function< ReturnType ( Args... ) >;
template < typename... Args >
static ReturnType Create( Args... args )
{
return Creator< decltype( args )... >()( args... );
}
template < typename... Args >
static void ResetToDefaultCreator()
{
Creator< Args... >() = &DefaultCreator< Args... >;
}
template < typename... Args >
static void SetCreator( CreatorFn< Args... > fn )
{
Creator< Args... >() = fn;
}
private:
Factory() = delete;
template < typename... Args >
static CreatorFn< Args... >& Creator()
{
static_assert( ( std::is_same< Args, std::decay_t< Args > >::value && ... ), "None of creator arguments can have a reference.");
static CreatorFn< Args... > creator = &DefaultCreator< Args... >;
return creator;
}
template < typename... Args >
static ReturnType DefaultCreator( Args... args )
{
return std::make_shared< T >( args... );
}
};
Sometimes you want a function to return multiple values. One very common way to
achieve such a behavior in C++ is to pass your values by non-const reference and
assign to them in your function:
void foo(int & a, int & b)
{
a = 1; b = 2;
}
Which you would use:
int a, b;
foo(a, b);
// do something with a and b
Now I have a functor that accepts such a function and would want to forward the
set arguments into another function returning the result:
template <typename F, typename G>
struct calc;
template <
typename R, typename ... FArgs,
typename G
>
struct calc<R (FArgs...), G>
{
using f_type = R (*)(FArgs...);
using g_type = G *;
R operator()(f_type f, g_type g) const
{
// I would need to declare each type in FArgs
// dummy:
Args ... args;
// now use the multiple value returning function
g(args...);
// and pass the arguments on
return f(args...);
}
};
Does this approach even make sense, or should I rather use a tuple based
approach? Is there something smarter than a tuple based approach here?
You could use compile-time indices:
template< std::size_t... Ns >
struct indices
{
typedef indices< Ns..., sizeof...( Ns ) > next;
};
template< std::size_t N >
struct make_indices
{
typedef typename make_indices< N - 1 >::type::next type;
};
template<>
struct make_indices< 0 >
{
typedef indices<> type;
};
template< typename F, typename G >
struct calc;
template<
typename R, typename ... FArgs,
typename G
>
struct calc< R (FArgs...), G >
{
using f_type = R (*)(FArgs...);
using g_type = G *;
private:
template< std::size_t... Ns >
R impl(f_type f, g_type g, indices< Ns... > ) const
{
std::tuple< FArgs ... > args;
g( std::get< Ns >( args )... );
// alternatively, if g() returns the tuple use:
// auto args = g();
return f( std::get< Ns >( args )... );
}
public:
R operator()(f_type f, g_type g) const
{
return impl( f, g, typename make_indices< sizeof...( FArgs ) >::type() );
}
};
When accepting the fact that we're changing the signature of both f and g to work with std::tuple, the answer to this problem becomes trivial:
template <typename F, typename G> struct calc;
template <typename R, typename ... Args>
struct calc<R (std::tuple<Args...> const &), std::tuple<Args...> ()>
{
using f_type = R (*)(std::tuple<Args...> const &);
using g_type = std::tuple<Args...> (*)();
R operator()(f_type f, g_type g) const
{
return f(g());
}
};
Here is a simple example:
int sum(std::tuple<int, int> const & t) { return std::get<0>(t) + std::get<1>(t); }
std::tuple<int, int> gen() { return std::make_tuple<int, int>(1, 2); }
auto x = calc<decltype(sum), decltype(gen)>()(&sum, &gen);
The limitation of this solution is clear however: you have to write your own functions. Using something like std::pow as f is not possible using this approach.
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
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 );
}
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;
}