mirt
mirt

Reputation: 1493

Strange template struct definition

I'm exploring the boost library code and found the following strange struct definition.

struct add_ints_only
{
    template<typename T>
    struct result;

    template <typename State, typename T>
    struct result<add_ints_only(State, T)> // what's going on here?
    {
        typedef typename boost::remove_const<
            typename boost::remove_reference<State>::type>::type type;
    };

    template <typename State, typename T> 
    State
    operator()(State const& state, T const& /*x*/) const
    {
        return state;
    }

    int
    operator()(int state, int x) const
    {
        return x + state;
    }
};

What is it for?

Upvotes: 3

Views: 403

Answers (2)

Evgeny Panasyuk
Evgeny Panasyuk

Reputation: 9199

I guess you are looking to some Boost.Fusion stuff or something similar.

In particular add_ints_only is model of Polymorphic Function Object concept.

Polymorphic Function Object provides polymorphic operator(), which may be overloaded or may be a template. Result type of operator() may differ based on it's parameter types.

It is similar in something to Adaptable Unary Function concept from STL, which should provide nested ::result_type.

But result type of Polymorphic Function Object may differ depending on arguments types passed to operator(). So, some more powerfull facility than single ::result_type should be used to get result type based on types of arguments of operator().

template <typename State, typename T>
struct result<add_ints_only(State, T)> // ...

This syntax is partial specialization of class.

add_ints_only(State, T)

Is type of function which returns add_ints_only and takes Stage and T as a parameter.

Itself, this type is not not meaningfull - you are not going to return add_ints_only. It is just convenient form of type argument passing - it looks like call of add_ints_only function. And it allow to have specialization for different numbers of arguments.

Here how it works:

live demo

#include <boost/utility/result_of.hpp>
#include <typeinfo>
#include <iostream>
#include <ostream>

using namespace std;

struct PolymorphicFunctionObject
{
    template<typename T> struct result;

    template<typename Arg>
    struct result< PolymorphicFunctionObject(Arg) >
    {
        typedef Arg type;
    };

    template<typename Arg1,typename Arg2>
    struct result< PolymorphicFunctionObject(Arg1,Arg2) >
    {
        typedef Arg2 type;
    };

    template<typename Arg>
    Arg operator()(Arg t) const
    {
        return t;
    }

    template<typename Arg1,typename Arg2>
    Arg2 operator()(Arg1 t1,Arg2 t2) const
    {
        return t2;
    }
};

int main()
{
    cout << typeid
    (
        PolymorphicFunctionObject::result< PolymorphicFunctionObject(int) >::type
    ).name() << endl;
    // Output is - int

    cout << typeid
    (
        PolymorphicFunctionObject::result< PolymorphicFunctionObject(char,double) >::type
    ).name() << endl;
    // Output is - double

    // -----------------
    // Or using boost::result_of, which queries ::result internally:

    cout << typeid
    (
        boost::result_of< PolymorphicFunctionObject(short) >::type
    ).name() << endl;
    // Output is - short

    cout << typeid
    (
        boost::result_of< PolymorphicFunctionObject(char,float) >::type
    ).name() << endl;
    // Output is - float

    // ------------------
    // Or using C++11 decltype:
    cout << typeid
    (
        decltype( PolymorphicFunctionObject()( long() ) )
    ).name() << endl;
    // Output is - long

    cout << typeid
    (
        decltype( PolymorphicFunctionObject()( long(),unsigned() ) )
    ).name() << endl;
    // Output is - unsigned int

}

As you can see, result type querying syntax:

boost::result_of< PolymorphicFunctionObject(short) >::type
boost::result_of< PolymorphicFunctionObject(char,float) >::type

Looks similar to normal function call.

P.S. In C++11 this stuff is not need, due to presence of decltype, which can be used to get type of result automatically. For instance:

decltype( PolymorphicFunctionObject()( long(),unsigned() ) )

Upvotes: 3

ecatmur
ecatmur

Reputation: 157334

result is partially specialized on the function type add_ints_only(State, T).

The purpose is that code that wants to know the type that the functor add_ints_only returns with particular argument types can inquire by writing:

typedef typename add_ints_only::result<add_ints_only(arg1_type, arg2_type)>::type
  result_type;

e.g.

template<typename U, typename V> void foo(U u, V v) {
  typename add_ints_only::result<add_ints_only(arg1_type, arg2_type)>::type
    result = add_ints_only()(u, v);
}

This is useful for functors that can return different types depending on their operator() argument types.

Upvotes: 3

Related Questions