[ ] C++17 |
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;
};
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));
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 });
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);
}
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);
}
for (Shape& shape: shapes)
{
visit(make_visitor([]](auto& c) { c.Print(); }), shape);
}
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);
};
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(); });
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();
});
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
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;
}
};
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{});
}
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); };
});
}
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