https://github.com/bfgroup/duck_invoke
A simple to use, single header, tag_invoke utility for C++11.
https://github.com/bfgroup/duck_invoke
cpp cpp11 cpp14 cpp17 cpp20 header-only
Last synced: 5 months ago
JSON representation
A simple to use, single header, tag_invoke utility for C++11.
- Host: GitHub
- URL: https://github.com/bfgroup/duck_invoke
- Owner: bfgroup
- License: bsl-1.0
- Created: 2020-06-30T15:44:55.000Z (almost 6 years ago)
- Default Branch: develop
- Last Pushed: 2022-11-27T03:11:30.000Z (over 3 years ago)
- Last Synced: 2025-05-05T19:04:04.959Z (11 months ago)
- Topics: cpp, cpp11, cpp14, cpp17, cpp20, header-only
- Language: C++
- Homepage: https://bfgroup.github.io/duck_invoke/
- Size: 7.41 MB
- Stars: 16
- Watchers: 5
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.adoc
- Funding: .github/FUNDING.yml
- License: LICENSE.txt
Awesome Lists containing this project
README
= Duck Invoke
// tag::intro[]
[.tagline]
A simple to use, single header, `tag_invoke` utility for C++11.
[horizontal.shields]
Obtain:: image:https://img.shields.io/github/downloads/bfgroup/duck_invoke/total.svg?label=GitHub[GitHub All Releases, link="https://github.com/bfgroup/duck_invoke/releases"]
License:: image:https://img.shields.io/badge/license-BSL%201.0-blue.svg["Boost Software License 1.0", link="LICENSE.txt"]
Standards:: image:https://img.shields.io/badge/standard-PFL-orange.svg["Pitchfork Layout", link="https://github.com/vector-of-bool/pitchfork"]
image:https://img.shields.io/badge/standard-C%2B%2B%2011-blue.svg?logo=C%2B%2B["C\+\+ 11", link="https://isocpp.org/"]
image:https://img.shields.io/badge/standard-C%2B%2B%2014-blue.svg?logo=C%2B%2B["C\+\+ 14", link="https://isocpp.org/"]
image:https://img.shields.io/badge/standard-C%2B%2B%2017-blue.svg?logo=C%2B%2B["C\+\+ 17", link="https://isocpp.org/"]
image:https://img.shields.io/badge/standard-C%2B%2B%2020-blue.svg?logo=C%2B%2B["C\+\+ 20", link="https://isocpp.org/"]
Stats:: image:https://img.shields.io/github/languages/code-size/bfgroup/duck_invoke.svg[GitHub code size in bytes, link="https://github.com/bfgroup/duck_invoke"]
image:https://img.shields.io/github/issues/bfgroup/duck_invoke.svg[GitHub issues, link="https://github.com/bfgroup/duck_invoke/issues"]
image:https://img.shields.io/github/stars/bfgroup/duck_invoke.svg?label=%E2%98%85[GitHub stars, link="https://github.com/bfgroup/duck_invoke/stargazers"]
// end::intro[]
== License
// tag::license[]
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// end::license[]
== Features
// tag::features[]
* Header only with no external dependencies (except the `std` library).
* Single header, with included reference documentation.
* BSL 1.0 license, so it can be used anywhere.
* Gives equivalent functionality, with less user code, than current C++20
`tag_invoke` implementations.
* For the most common, and basic, use case it's a single line of code.
* Fully optimizes, with `-O2`, to equivalent direct code.
* Tested to work with: Linux GCC 4.8 through 10; Linux Clang 3.8 through 11;
macOS Xcode 11.2.1 through 12.2; Windows MinGW-w64 7.3 and 6.3;
Windows 2019 (currently only works with `/std:c++latest` option).
// end::features[]
== Using
// tag::using[]
The simplest use case involves a few simple items:
. The definition of the customization point object (CPO).
. Calling the CPO in a library that wants to be customized by users of it.
. Defining a customization in code that uses the library.
. Calling the library to use the feature that is customized.
(1) With this library the definition of the CPO is a simple single declaration:
[source,cpp]
----
#include
namespace compute {
BFG_TAG_INVOKE_DEF(formula);
} // namespace compute
----
That has the effect of declaring `compute::formula_t` for the CPO tag type.
And defines a `compute::formula` CPO that can be called. And that is
customizable through `tag_invoke` functions.
(2) Using the CPO in the library code, or even in user code, is as simple as
calling the CPO like a regular call:
[source,cpp]
----
template
float do_compute(const Compute & c, float a, float b)
{
return compute::formula(c, a, b);
}
----
The key aspect for defining such code in libraries is that you need to accept
an argument for which the type is used for argument dependent lookup (ADL)
resolution. In this example the `const Compute & c` argument will do that for
us.
(3) We can now turn our attention to the user code of the above "library". For
that we need to create an object that provides a customization of the
appropriate customization point. The most effective way to do that is with a
hidden friend function:
[source,cpp]
----
struct custom_compute
{
private:
friend float
tag_invoke(compute::formula_t, const custom_compute &, float a, float b)
{
return a * b;
}
};
----
The arguments match the use of the CPO in the library, plus the tag type of
the CPO as the first argument. That argument is what puts the customization
within the realm of ADL.
(4) Finally we can use the library and the customization we created for it:
[source,cpp]
----
int main()
{
do_compute(custom_compute{}, 2, 3);
}
----
// end::using[]