-

   rss_rss_hh_new

 - e-mail

 

 -

 LiveInternet.ru:
: 17.03.2011
:
:
: 51

:


[ ] C++17

, 01 2017 . 20:25 +
, ! C++17, . C++. , . , , 14 modern .

(3 (apply, filter, reduce) (map) :)) ( std::variant 17 ).

, , fold expressions structured binding


. , , c++ . std::tuple, (not pay for what you don't use) . .

, std::any std::variant. , . std::variant std::visit ( ). , , , :) ( , c++ ). std::variant , boost ( , ). , std::variant .


. , . , .

, :)


. :

struct Circle
{
    void Print() { cout << "Circle. " << "Radius: " << radius << endl; }
    double Area() { return 3.14 * radius * radius; }

    double radius;
};

struct Square
{
    void Print() { cout << "Square. Side: " << side << endl; }
    double Area() { return side * side * side * side; }

    double side;
};

struct EquilateralTriangle
{
    void Print() { cout << "EquilateralTriangle. Side: " << side << endl; }
    double Area() { return (sqrt(3) / 4) * (side * side); }

    double side;
};

using Shape = variant;

:

struct Shape
{
    virtual void Print() = 0;
    virtual double Area() = 0;
    virtual ~Shape() {};
};

struct Circle : Shape
{
    Circle(double val) : radius(val) {}

    void Print() override { cout << "Circle. " << "Radius: " << radius << endl; }
    double Area() override { return 3.14 * radius * radius; }

    double radius;
};

struct Square : Shape
{
    Square(double val) : side(val) {}

    void Print() override { cout << "Square. Side: " << side << endl; }
    double Area() override { return side * side * side * side; }

    double side;
};

struct EquilateralTriangle : Shape
{
    EquilateralTriangle(double val) : side(val) {}

    void Print() override { cout << "EquilateralTriangle. Side: " << side << endl; }
    double Area() override { return (sqrt(3) / 4) * (side * side); }

    double side;
};

. Print.

( ). , :

vector shapes;
shapes.emplace_back(new Square(8.2));
shapes.emplace_back(new Circle(3.1));
shapes.emplace_back(new Square(1.8));
shapes.emplace_back(new EquilateralTriangle(10.4));
shapes.emplace_back(new Circle(5.7));
shapes.emplace_back(new Square(2.9));

. new . :

vector> shapes;
shapes.emplace_back(make_shared(8.2));
shapes.emplace_back(make_shared(3.1));
shapes.emplace_back(make_shared(1.8));
shapes.emplace_back(make_shared(10.4));
shapes.emplace_back(make_shared(5.7));
shapes.emplace_back(make_shared(2.9));

. . , :

for (shared_ptr shape: shapes)
{
    shape->Print();
}

// :
// Square. Side: 8.2
// Circle. Radius: 3.1
// Square. Side: 1.8
// EquilateralTriangle. Side: 10.4
// Circle. Radius: 5.7
// Square. Side: 2.9

:

vector operations;
operations.emplace_back(EquilateralTriangle { 5.6 });
operations.emplace_back(Square { 8.2 });
operations.emplace_back(Circle { 3.1 });
operations.emplace_back(Square { 1.8 });
operations.emplace_back(EquilateralTriangle { 10.4 });
operations.emplace_back(Circle { 5.7 });
operations.emplace_back(Square { 2.9 });

. . aggregate initialization .

. , std::variant. std::visit, .

:

struct Visitor
{
    void operator()(Circle& c) { c.Print(); }
    void operator()(Square& c) { c.Print(); }
    void operator()(EquilateralTriangle& c) { c.Print(); }
};

...
...
...

for (Shape& shape: shapes)
{
    visit(Visitor{}, shape);
}

. constexpr if. .

, , .

: apply, filter, reduce.

1


. .
variadic templates, , - . , :

template < typename... Func >
class Visitor : Func... { using Func::operator()...; }
template < class... Func > make_visitor(Func...) -> Visitor < Func... >;

, :

for (Shape& shape: shapes)
{
    visit(make_visitor(
                        []](Circle& c) { c.Print(); },
                        []](Square& c) { c.Print(); },
                        []](EquilateralTriangle& c) { c.Print(); }
                      ), shape);
}

generic :

for (Shape& shape: shapes)
{
    visit(make_visitor([]](auto& c) { c.Print(); }), shape);
}

.

Apply


apply :

template <
           typename InputIter,
           typename InputSentinelIter,
           typename... Callable
         >
void apply(InputIter beg,
           InputSentinelIter end,
           Callable... funcs)
{
    for (auto _it = beg; _it != end; ++_it)
        visit(make_visitor(funcs...), *_it);
};

. , , boost::variant http://en.cppreference.com/w/cpp/utility/variant/visit, https://habrahabr.ru/post/270689/).

:

apply(shapes.begin(), shapes.end(), [](auto& shape) { shape.Print(); });



apply(shapes.begin(), shapes.end(), 
      [] (Circle& shape)              { shape.Print(); },
      [] (Square& shape)              { shape.Print(); },
      [] (EquilateralTriangle& shape) { shape.Print(); });

, . , , std::variant, . , SFINAE elipsis, , .

template <
           typename InputIter,
           typename InputSentinelIter,
           typename... Callable
         >
void apply(InputIter beg,
           InputSentinelIter end,
           Callable... funcs)
{
    for (auto _it = beg; _it != end; ++_it)
        visit(make_visitor(funcs..., [](...){}), *_it);
};

, :

//      Circle
apply(shapes.begin(), shapes.end(), [] (Circle& shape) { shape.Print(); }); 

, :

//      Circle
for_each(shapes.begin(), shapes.end(),
         [] (shared_ptr shape) {
             if (dynamic_pointer_cast(shape))
                    shape->Print();
         });

.

Filter


filter. , , elipsis bool. , , , .

template <
           typename InputIter,
           typename InputSentinelIter,
           typename OutputIter,
           typename... Callable
         >
void filter(InputIter beg,
            InputSentinelIter end,
            OutputIter out,
            Callable... funcs)
{
    for (auto _it = beg; _it != end; ++_it)
    {
        if (visit(make_visitor(funcs..., [] (...) { return false; }), 
                  *_it))
            *out++ = *_it;
    }
};

:

vector filtered;
filter(shapes.begin(), shapes.end(),
       back_inserter(filtered),
       [] (Circle& c) { return c.radius > 4.; },
       [] (Square& s) { return s.side < 5.; });

apply(filtered.begin(), filtered.end(), [](auto& shape) { shape.Print(); });

// :
// Square. Side: 1.8
// Circle. Radius: 5.7
// Square. Side: 2.9

, :

vector> filtered;
copy_if(shapes.begin(), shapes.end(),
        back_inserter(filtered),
        [] (shared_ptr shape)
        {
            if (auto circle = dynamic_pointer_cast(shape))
            {
                return circle->radius > 4.;
            }
            else if (auto square = dynamic_pointer_cast(shape))
            {
                return square->side < 5.;
            }
            else return false;
        });

for_each(filtered.begin(), filtered.end(), [](shared_ptr shape) { shape->Print(); });

// :
// Square. Side: 1.8
// Circle. Radius: 5.7
// Square. Side: 2.9

Reduce


reduce ( std::accumulate) map ( std::transform). , apply filter. reduce ( ). , , , std::variant . c++ , . , , variadic pack, . fold expressions. , .

template <
           typename InputIter,
           typename InputSentinelIter,
           typename AccType,
           typename... Callable
         >
struct reduce < InputIter, InputSentinelIter, AccType, false, Callable... >
{
    constexpr auto operator()(InputIter beg, InputSentinelIter end,
                              AccType initial_acc, Callable... funcs)
    {
        for (auto _it = beg; _it != end; ++_it)
        {
            initial_acc = visit(utility::make_overloaded_from_tup(
                tup_funcs(initial_acc, funcs...),
                make_index_sequence{},
                [&initial_acc] (...) { return initial_acc; } ),
                                *_it);
        }
        return initial_acc;
    }
};

, , (std::tuple). , . , , . , , :

template < typename... Types, typename Func, size_t... I >
constexpr auto tuple_transform_impl(tuple t, Func func, index_sequence)
{
    return make_tuple(func(get(t)...));
}

template < typename... Types, typename Func >
constexpr auto tuple_transform(tuple t, Func f)
{
    return tuple_transform_impl(t, f make_index_sequence{});
}

, , . helper', , , .

:

template < typename Func, typename Ret, typename _, typename A, typename... Rest >
A _sec_arg_hlpr(Ret (Func::*)(_, A, Rest...));

template < typename Func >
using second_argument = decltype(_sec_arg_hlpr(&Func::operator()));

template < typename AccType, typename... Callable >
constexpr auto tup_funcs(AccType initial_acc, Callable... funcs)
{
    return tuple_transform(tuple{ funcs... },
        [&initial_acc](auto func) {
            return [&initial_acc, &func] (second_argument arg) {
                return func(initial_acc, arg); };
        });
}

, generic , . , tag dispatching .
, reduce :

using ShapeCountT = tuple;
auto result = reduce(shapes.begin(), shapes.end(),
                     ShapeCountT{},
                     [] (ShapeCountT acc, Circle& item)
                     {
                         auto [cir, sq, tr] = acc;
                         return make_tuple(++cir, sq, tr);
                     },
                     [] (ShapeCountT acc, Square& item)
                     {
                         auto [cir, sq, tr] = acc;
                         return make_tuple(cir, ++sq, tr);
                     },
                     [] (ShapeCountT acc, EquilateralTriangle& item)
                     {
                         auto [cir, sq, tr] = acc;
                         return make_tuple(cir, sq, ++tr);
                     });
auto [cir, sq, tr] = result;
cout << "Circle count: " << cir
     << "\tSquare count: " << sq
     << "\tTriangle count: " << tr << endl;

// :
// Circle count: 2 Square count: 3 Triangle count: 2

map , . meta :)

?


. :



, ( generic ). , .

, .
Concepts TS gcc-7.1.

, , , TypeErasure , , ,

/ ? ,

.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332084/

:  

: [1] []
 

:
: 

: ( )

:

  URL