.. include:: Writing Your Own Concepts ========================= .. contents:: :local: Starting Point: Good Old Function --------------------------------- * N-dimensional hypotenuse, over ``std::vector`` * Uses * ``v.size()`` * ``v.operator[]()`` .. literalinclude:: code/hypotenuse-good-old-function.cpp :caption: :download:`code/hypotenuse-good-old-function.cpp` :language: c++ Problem: ``std::vector`` Is Not Enough |longrightarrow| Template ------------------------------------------------------------------------ * ``point2d``: members ``x, y`` (and potentially some operations on a point, but that is not the point here) * |longrightarrow| Turn ``hypotenuse()`` into a template * *Straightforward* * |longrightarrow| Errors deep down in the implementation .. literalinclude:: code/hypotenuse-template-no-concept-error.cpp :caption: :download:`code/hypotenuse-template-no-concept-error.cpp` :language: c++ .. code-block:: console error: ‘const class point2d’ has no member named ‘size’ 9 | for (size_t i=0; i’ [with V = point2d] Fix ``has_size`` Failure In ``point2d`` --------------------------------------- * Fix: add ``point2d::size()`` as required * Still old-school-complains about ``operator[]`` .. literalinclude:: code/hypotenuse-template-concept-has_size-fixed.cpp :caption: :download:`code/hypotenuse-template-concept-has_size-fixed.cpp` :language: c++ Problem: What If I Pass Elements That Do Not Support ``*``? ----------------------------------------------------------- * E.g.: ``std::vector`` * Which is nonsense because vector (in its math sense) coordinates must be *multipliable* * |longrightarrow| does not support ``operator*()`` .. literalinclude:: code/hypotenuse-coordinate-not-multipliable-error.cpp :caption: :download:`code/hypotenuse-coordinate-not-multipliable-error.cpp` :language: c++ .. code-block:: console error: no match for ‘operator*’ (operand types are ‘const __gnu_cxx::__alloc_traits >, std::pair >::value_type’ {aka ‘const std::pair’} and ‘const __gnu_cxx::__alloc_traits >, std::pair >::value_type’ {aka ‘const std::pair’}) 17 | sumsq += v[i]*v[i]; | ~~~~^~~ Concept: ``coordinate_is_multipliable`` --------------------------------------- * Again, require this explicitly * |longrightarrow| result of ``operator[]`` must support multiplication * |longrightarrow| this is exactly how the concept looks .. literalinclude:: code/hypotenuse-coordinate-not-multipliable-concept-error.cpp :caption: :download:`code/hypotenuse-coordinate-not-multipliable-concept-error.cpp` :language: c++ .. code-block:: console note: constraints not satisfied In substitution of ‘template double hypotenuse(const V&) requires (has_size) && (coordinate_is_multipliable) [with V = std::vector >]’: required from here required for the satisfaction of ‘coordinate_is_multipliable’ [with V = std::vector, std::allocator > >] in requirements with ‘V v’ [with V = std::vector, std::allocator > >] note: the required expression ‘(v[0] * v[0])’ is invalid 13 | v[0]*v[0]; // <-- as a requirement, this must compile | ~~~~^~~ Concept: Require Coordinate Type To Be Double --------------------------------------------- .. sidebar:: Documentation * `std::same_as `__ * `Concepts library (since C++20) `__ * Rationale: because I can |:muscle:| * There is no real reason but to show another syntactical highlight * ... and some usage of ```` .. literalinclude:: code/hypotenuse-coordinate-concept-must-be-double.cpp :caption: :download:`code/hypotenuse-coordinate-concept-must-be-double.cpp` :language: c++ .. code-block:: console note: constraints not satisfied In substitution of ‘template double hypotenuse(const V&) requires contains_double_likes [with V = std::vector >]’: required from here required for the satisfaction of ‘contains_double_likes’ [with V = std::vector >] in requirements with ‘V v’ [with V = std::vector >] note: ‘v[0]’ does not satisfy return-type-requirement 9 | { v[0] } -> std::same_as; | ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~