Boost C++ Libraries

PrevUpHomeNext

Forwarding Strategies

Argument list
by_perfect
by_ref
by_cref
by_value
Writing your own strategies
Determining nullary return types

A Forwarding Strategy is a type which has three associated imaginary operators __bytag_at, __arg_list and __meta_arg_list. Egg predefines the fundamental strategy quartet: by_perfect, by_ref, by_cref, and by_value. Also note Egg components use by_perfect when you omit or specify boost::use_default for strategy parameter.

This section uses the following notation.

Valid expression

Semantics

__arg(a)

__typeof(a) const if a is a rvalue; boost::remove_reference<__decltype(a)>::type otherwise.

__ref(a)

static_cast<__arg(a) &>(a)

__cref(a)

static_cast<__arg(a) const &>(a)

__val(a)

const_cast<V &>(static_cast<V const &>(boost::implicit_cast<V>(a)))

__rval(a)

boost::implicit_cast<V>(a)

, where V is boost::remove_cv<boost::decay<__typeof(a)>::type>::type.

[Caution] Caution

Under msvc-7.1, a in __cref(a) can't be function name. It is preferable to add a & then turn the function name into function pointer.

Description

Egg defines the following imaginary operators for its documentation.

Notation
Valid expressions

Valid expression

Semantics

__bytag_at(__Stg, K, I)

See each section of __Stg.

__arg_list(a, __Stg)

See each section of __Stg.

__arg_list(a, __ud)

__arg_list(a, by_perfect)

__meta_arg_list(a, __Stg)

See each section of __Stg.

__meta_arg_list(a, __ud)

__meta_arg_list(a, by_perfect)

__fwd_arg_list(a, __Stg)

fwd_arg(a, __Stg, K, 0),...,fwd_arg(a, __Stg, K, K-1)

[Important] Important

__arg_list and __fwd_arg_list have slightly different semantics. Put simply, in the case of Function Adaptors with by_value, a "base" Function Object too must take its arguments by value or const reference.

See also
Description

Egg performs "perfect forwarding" by default.

Header
  • <boost/egg/by_perfect.hpp>
Notation
  • remove_cr(x) is boost::remove_const<boost::remove_reference<__decltype(x)>::type>::type.
  • bI is any object such that remove_cr(bI) is the same as remove_cr(aI).
Valid expressions

Valid expression

Semantics

__bytag_at(by_perfect, K, I)

by_perfect

__arg_list(a, by_perfect)

__arg(a1),...,__arg(aK)

__meta_arg_list(a, by_perfect)

__ref(a1),...,__ref(aK)

function<__Lit, by_perfect>

See function.

Preconditions
  • 0 <= K && K <= BOOST_EGG_MAX_ARITY.
  • If Expr(__arg_list(a, by_perfect)) is a precondition as valid expression, Expr(__arg_list(b, by_perfect)) must be well-formed.
  • If Expr(__meta_arg_list(a, by_perfect)) is a precondition as valid expression, Expr(__meta_arg_list(b, by_perfect)) must be well-formed.
Example
  • __meta_arg_list(a, by_perfect) is int,const int,int const if a is i,3,ci, where i is a non-const lvalue and ci is a const lvalue.
See also
Description

by_ref offers large arity, but can't take non-const rvalues.

Header
  • <boost/egg/by_ref.hpp>
Valid expressions

Valid expression

Semantics

__bytag_at(by_ref, K, I)

by_ref

__arg_list(a, by_ref)

__arg(a1),...,__arg(aK)

__meta_arg_list(a, by_ref)

__ref(a1),...,__ref(aK)

function<__Lit, by_ref>

See function.

Preconditions
  • 0 <= K && K <= BOOST_EGG_MAX_LINEAR_ARITY.
  • aI is not a rvalue.
Example
  • __meta_arg_list(a, by_ref) is int,const int,int const if a is i,ci,ci, where i is a non-const lvalue and ci is a const lvalue.
See also
Description

by_cref takes arguments by const reference.

Header
  • <boost/egg/by_cref.hpp>
Valid expressions

Valid expression

Semantics

__bytag_at(by_cref, K, I)

by_cref

__arg_list(a, by_cref)

__cref(a1),...,__cref(aK)

__meta_arg_list(a, by_cref)

__typeof(a1) const,...,__typeof(aK) const

function<__Lit, by_cref>

See function.

Preconditions
  • 0 <= K && K <= BOOST_EGG_MAX_LINEAR_ARITY.
Example
  • __meta_arg_list(a, by_cref) is int const,const int,int const if a is i,ci,ci, where i is a non-const lvalue and ci is a const lvalue.
See also
Description

by_value takes arguments by value so that arguments are "decayed". Also, it can forward "movable" rvalues like std::auto_ptr<> with keeping movability.

Header
  • <boost/egg/by_value.hpp>
Valid expressions

Valid expression

Semantics

__bytag_at(by_value, K, I)

by_value

__arg_list(a, by_value)

__val(a1),...,__val(aK)

__meta_arg_list(a, by_value)

__typeof(a1),...,__typeof(aK)

function<__Lit, by_value>

See function.

Preconditions
  • 0 <= K && K <= BOOST_EGG_MAX_LINEAR_ARITY.
Example
  • __meta_arg_list(a, by_value) is int,int,int if a is i,3,ci, where i is a non-const lvalue and ci is a const lvalue.
Forwarded arguments are mutable.

by_value copies arguments and turns them into mutable lvalues so that generic Little Functions can be written. But, if you know by_value is used, Little Function call should take arguments "by value" or const reference:

struct little_id;
typedef function<little_id, by_value> T_id; 1

struct little_id
{
    template<class Me, class V>
    struct apply
    {
        typedef V type;
    };

    template<class Re, class V>
    Re call(V v) const 2
    {
        return v;
    }
};

1

Takes arguments by value.

2

Re call(V &v) const is allowed, but unrecommended.

See also
Description

The predefined strategies, by_perfect etc, may be too simple to meet your requirements. Egg provides a uniform way to define your own strategies.

Header
  • <boost/egg/function_extension.hpp>
Valid expressions

Valid expression

Semantics

BOOST_EGG_FUNCTION_PREAMBLE()

See below.

apply_little<Lit, A1,...,AK>::type

Lit::nullary_result_type if K == 0; Lit::apply<Lit, A1,...,AK>::type otherwise.

call_little(__lit, a1,...,aK)

__lit.call<apply_little<__meta_arg_list([__lit]++a, by_ref)>::type>(a1,...,aK)

by_perfect, by_ref, by_cref, and by_value

These can be used as "meta" return type of strategy tag.

BOOST_EGG_FUNCTION_CALL_OPERATOR(Bytags, Cv)

See below.

BOOST_EGG_DEDUCED_CONST(T)

T const

Preconditions
  • Bytags is a Preprocessor Sequence of __Bytag.
  • Cv is cv-qualifier of call operator. In case of no cv-qualifiers, Cv must be mutable.
  • Cv must be const (for now).
  • 0 <= K && K <= BOOST_EGG_MAX_LINEAR_ARITY.
Your strategy tag

A user-defined strategy tag is MPL Metafunction Class which takes itself, arity and index, then returns __Bytag.

struct your_strategy
{
    template<class _, class Arity, class Index>
    struct apply;

    typedef boost::mpl::vector<by_perfect, by_ref> arity2_bytags;

    template<class _, class Index>
    struct apply<_, boost::mpl::int_<2>, Index> :
        boost::mpl::at<arity2_bytags, Index>
    { };

    template<class _, class Index>
    struct apply<_, boost::mpl::int_<3>, Index>
    {
        typedef by_value type;
    };
};

Specializing function<>

Using your strategy tag, function<> template can be specialized. BOOST_EGG_FUNCTION_PREAMBLE() must be placed in first, which automagically defines nested typedefs little_type, strategy_type, and result<...> etc.

namespace boost { namespace egg {

    template<class Lit>
    struct function<Lit, your_strategy>
    {
        BOOST_EGG_FUNCTION_PREAMBLE() 1

        Lit m_lit;
        Lit const & little() const { return m_lit; }

    // 0ary
        typename apply_little<Lit const>::type 2
        operator()() const
        {
            return call_little(m_lit);
        }

    // 2ary: by_perfect, by_ref
        BOOST_EGG_FUNCTION_CALL_OPERATOR((by_perfect)(by_ref), const)
#if 0   // Macro above is expaneded to...
        template<class A0, class A1>
        typename apply_little<Lit const, A0, A1>::type
        operator()(A0 &a0, A1 &a1) const
        {
            return call_little(m_lit, a0, a1);
        }

        template<class A0, class A1>
        typename apply_little<Lit const, BOOST_EGG_DEDUCED_CONST(A0), A1>::type 3
        operator()(A0 const &a0, A1 &a1) const
        {
            return call_little(m_lit, a0, a1);
        }
#endif

    // 3ary: by_value
        template<class A0, class A1, class A2>
        typename apply_little<Lit const, A0, A1, A2>::type
        operator()(A0 a0, A1 a1, A2 a2) const
        {
            return call_little(m_lit, a0, a1, a2);
        }
    };

} }

1

This must be placed first.

2

apply_little requires _Lit to be const-correct.

3

BOOST_EGG_DEDUCED_CONST works around msvc-7.1 array bug.

For by_perfect call operators, it is easy and preferable to use BOOST_EGG_FUNCTION_CALL_OPERATOR, which will compile much faster in C++0x. Also note, in order to work around some compiler bugs, you can use neither result template nor __Lit::call directly. You have to use apply_little and call_little instead. Moreover, if you want to support buggy msvc-7.1, BOOST_EGG_DEDUCED_CONST instead of const must be used in apply_little.

Your strategy completed

Now function<> with your strategy is a model of Major Function Object. Let's look into the new valid expressions.

Notation
New valid expressions

Valid expression

Semantics

__bytag_at(StgTag, K, I)

StgTag_::apply< StgTag_, __mpl::int_<K>, __mpl::int_<I> >::type

__arg_list(a, StgTag)

__arg_list([a1], __bytag_at(StgTag, K, 0))++...++__arg_list([aK], __bytag_at(StgTag, K, K-1))

__meta_arg_list(a, StgTag)

__meta_arg_list([a1], __bytag_at(StgTag, K, 0))++...++__meta_arg_list([aK], __bytag_at(StgTag, K, K-1))

function<__Lit, StgTag>

See function.

See also
Description

C++ instantiates the declarations of non-dependent member function templates, so that some Function Builders and Function Adaptors require a special workaround. Here an imaginary operator is defined for the documentation.

Valid expressions and semantics
  • __decltype_r0(R0, expr) is defined as follows:
    • If R0 is __ud, it is a valid expression and returns an unspecified type .
    • If R0 is use_nullary_result,
      • If __decltype(expr) is a valid expression, it is a valid expression and returns __decltype(expr).
      • Otherwise, it is not a valid expression.
    • Otherwise, R0.
[Tip] Tip

Boost.ResultOf too offers a special workaround: A nullary callable class F without nested result_type must specialize result_of<F()>. result_of<F()>::type is void otherwise. Unfortunately, that isn't generic workaround. Consider f(g(), h()) such that f isn't a 2ary function.

See also

PrevUpHomeNext