diff --git a/README.md b/README.md index e80205b..b2c371a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,71 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception Implements: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -## Building + +## Usage + +`std::identity` is a function object type whose `operator()` returns its argument unchanged. `std::identity` serves as the default projection in constrained algorithms. Its direct usage is usually not needed. + +### Example: default projection in constrained algorithms + + The following code snippet illustrates how we can achieve a default projection using `Beman::Example::identity`: + + +```cpp +#include + +// Class with a pair of values. +struct Pair +{ + int n; + std::string s; + + // Output the pair in the form {n, s}. + // Used by the range-printer if no custom projection is provided (default: identity projection). + friend std::ostream &operator<<(std::ostream &os, const Pair &p) + { + return os << "Pair" << '{' << p.n << ", " << p.s << '}'; + } +}; + +// A range-printer that can print projected (modified) elements of a range. +// All the elements of the range are printed in the form {element1, element2, ...}. +// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three} +// e.g., pairs with custom projection: {1:one, 2:two, 3:three} +template +void print(const std::string_view rem, R &&range, Projection projection = Beman::Example::identity>) +{ + std::cout << rem << '{'; + std::ranges::for_each( + range, + [O = 0](const auto &o) mutable + { std::cout << (O++ ? ", " : "") << o; }, + projection); + std::cout << "}\n"; +}; + +int main() +{ + // A vector of pairs to print. + const std::vector pairs = { + {1, "one"}, + {2, "two"}, + {3, "three"}, + }; + + // Print the pairs using the default projection. + std::cout << "Default projection:\n"; + print("\tpairs with Beman: ", pairs); + + return 0; +} + +``` + +Full runable examples can be found in `examples/` (e.g., [./examples/Beman/Beman.Example/examples/identity_as_default_projection.cpp.cpp](./examples/Beman/Beman.Example/examples/identity_as_default_projection.cpp.cpp)). + +## Building Beman.Example ### Dependencies diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c0e2b14..079101c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -set(ALL_EXAMPLES identity_usage) +set(ALL_EXAMPLES identity_as_default_projection identity_direct_usage) foreach(example ${ALL_EXAMPLES}) add_executable(${example} "") diff --git a/examples/identity_as_default_projection.cpp b/examples/identity_as_default_projection.cpp new file mode 100644 index 0000000..88f34f2 --- /dev/null +++ b/examples/identity_as_default_projection.cpp @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// This example demonstrates the usage of Beman::Example::identity as a default projection in a range-printer. +// Requires: range support (C++20) and std::identity support (C++20). +// TODO Darius: Do we need to selectively compile this example? +// Or should we assume that this project is compiled with C++20 support only? + +#include // Beman::Example::identity + +#include +#include // std::identity +#include +#include +#include + +// Class with a pair of values. +struct Pair +{ + int n; + std::string s; + + // Output the pair in the form {n, s}. + // Used by the range-printer if no custom projection is provided (default: identity projection). + friend std::ostream &operator<<(std::ostream &os, const Pair &p) + { + return os << "Pair" << '{' << p.n << ", " << p.s << '}'; + } +}; + +// A range-printer that can print projected (modified) elements of a range. +// All the elements of the range are printed in the form {element1, element2, ...}. +// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three} +// e.g., pairs with custom projection: {1:one, 2:two, 3:three} +template +void print_helper(const std::string_view rem, R &&range, Projection projection) +{ + std::cout << rem << '{'; + std::ranges::for_each( + range, + [O = 0](const auto &o) mutable + { std::cout << (O++ ? ", " : "") << o; }, + projection); + std::cout << "}\n"; +}; + +// Print wrapper with Beman::Example::identity. +template // <- Notice the default projection. +void print_beman(const std::string_view rem, R &&range, Projection projection = {}) +{ + print_helper(rem, range, projection); +} + +// Print wrapper with std::identity. +template // <- Notice the default projection. +void print_std(const std::string_view rem, R &&range, Projection projection = {}) +{ + print_helper(rem, range, projection); +} + +int main() +{ + // A vector of pairs to print. + const std::vector pairs = { + {1, "one"}, + {2, "two"}, + {3, "three"}, + }; + + // Print the pairs using the default projection. + std::cout << "Default projection:\n"; + print_beman("\tpairs with Beman: ", pairs); + print_std("\tpairs with std: ", pairs); + + // Print the pairs using a custom projection. + std::cout << "Custom projection:\n"; + print_beman("\tpairs with Beman: ", pairs, + [](const auto &p) + { return std::to_string(p.n) + ':' + p.s; }); + print_std("\tpairs with std: ", pairs, + [](const auto &p) + { return std::to_string(p.n) + ':' + p.s; }); + + return 0; +} diff --git a/examples/identity_usage.cpp b/examples/identity_direct_usage.cpp similarity index 100% rename from examples/identity_usage.cpp rename to examples/identity_direct_usage.cpp