https://github.com/willkill07/concepts-lighter
Concepts (with and without SFINAE) in C++11
https://github.com/willkill07/concepts-lighter
concepts cplusplus portability raja
Last synced: 12 months ago
JSON representation
Concepts (with and without SFINAE) in C++11
- Host: GitHub
- URL: https://github.com/willkill07/concepts-lighter
- Owner: willkill07
- License: other
- Created: 2017-06-28T00:46:42.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2017-07-03T17:14:52.000Z (over 8 years ago)
- Last Synced: 2025-02-24T04:13:16.447Z (12 months ago)
- Topics: concepts, cplusplus, portability, raja
- Language: C++
- Homepage:
- Size: 31.3 KB
- Stars: 2
- Watchers: 2
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Concepts Lighter
Basic concept-like functionality in C++11
See `example.cpp` for potential usage
*NOTE:* Most of this work is accomplished through original work done by Eric Niebler with `range-v3` and his concepts implementation. I enhanced and simplified the dependence on `meta` to only include relevant metafunctions. This work also leverages the `detector` idiom proposed in N4502.
## Goals
* Provide a concepts facility in C++11 without any third-party libraries
* Emulate the interface reasonably close
* Aim for high-throughput by prefering aliases to new struct definitions
## Non-Goals
* Provide a complete concepts replacement for use until Concepts are added to the C++ language
* Implement the entire Concepts TS and Ranges TS concept list
## Design
### A concept:
* is a type alias which when fully evaluated *can* produce a compiler error
* provides a protected evaluation context of arbitrary code
* only detects if operations exist and emit the correct type
### What can a concept do?
* checks if it models another concept (`models()`)
* checks if an expression is valid (`val() == val()`)
* checks if an expression has some result type (`has_type(expr)`)
* checks if an expression has some result type convertible to another (`convertible_to(expr)`)
### What can go in a concept expression?
* type helpers for creating instances of types which may not always be default constructible (`val`, `cval`, `ref`, `cref`
* any aribitrary code not dependent on any code out of the scope of the concept definition (can only use types)
### What is the syntax for a concept?
A concept first starts with defining the types of which the concept depends on. For example, if we are writing a concept that depends on an aribitrary value type, perhaps `typename Type` might be enough. If we are writing a concept to see if a type models an Iterator of some type, we may want to use `typename Iter`. If we need to check the relations between two types, we will need to define two types as template parameters: `typename T, typename U`
```cpp
template
using Iterator = // ...
```
So far that's our concept definition. We specified our template arguments and the name of our concept. Next we will look at defining some number of expressions required by `Iterator`. First we need to indicate we are writing a concept instead of a type alias.
```cpp
template
using Iterator = DefineConcept( ... );
// OR
template
using Iterator = decltype(concepts::valid_expr( ... ));
```
Either syntax is acceptable (`DefineConcept` is a macro). Now we need to determine what are valid expressions in the concept of an `Iterator`. According to the Ranges TS, an `Iterator` requires the functionality of pre-incrementing (`operator++`) and dereferencing (`operator*`).
Let us first look at normal usages:
```cpp
Iter i; // we have an instance of Iter
++i; // preincrement -- return type should be Iter&
*i; // dereference -- unspecified return type
```
Since we are not able to declare any variables in a type definition, we will leverage the `ref()` component provided in this concepts framework:
```cpp
concepts::has_type(++concepts::ref());
*concepts::ref();
```
We no longer have any variable definitions, and can easily replace the semicolons of separate statements to be comma-separated for our expression list:
```cpp
template
using Iterator = DefineConcept(
concepts::has_type(++concepts::ref()),
*concepts::ref()
);
```
This is a complete concept definition! Look further up at `ForwardIterator` to see extended implementations using `ref()`, `has_type(expr)`, and `models()`.
## Usage
A very simple usage pattern is illustrated below
```cpp
template
using LessThanComparable =
DefineConcept(
concepts::convertible_to(
concepts::val() < concepts::val())));
```
Please note that there are a few key components (and everything lives under `namespace concepts`:
* `concepts::valid_expr(...)` -- a function accepting a list of expressions to evaluate -- consider using the wrapper macro `DefineConcept(...)` instead
* `concepts::has_type(x)` -- a function accepting an expression that checks the return type and ensures it matches the passed type
* `concepts::convertible_to(x)` -- a function accepting an expression that checks the return type to a passed type for conversion
* `concepts::models()` -- a function accepting a fully-qualified concept name of which a new concept should model
* `concepts::val()` -- a function accepting a type that returns a `declval` instance of `T`
* `concepts::ref()` -- a function accepting a type that returns a `declval` instance of `T&`
* `concepts::cref()` -- a function accepting a type that returns a `declval` instance of `T const &`
* `concepts::cval()` -- a function accepting a type that returns a `declval` instance of `T const`
We are also able to easily check for total comparisons between any two types:
```cpp
template
using ComparableTo = DefineConcept(
convertible_to(val() < val()),
convertible_to(val() < val()),
convertible_to(val() <= val()),
convertible_to(val() <= val()),
convertible_to(val() > val()),
convertible_to(val() > val()),
convertible_to(val() >= val()),
convertible_to(val() >= val()),
convertible_to(val() == val()),
convertible_to(val() == val()),
convertible_to(val() != val()),
convertible_to(val() != val())));
template using Comparable = ComparableTo;
```
Below is an example of Iterator concepts using the convenience macro (and assuming `using namespace concepts`)
```cpp
template
using Iterator = DefineConcept(
*ref(), // checks dereference
has_type(++ref()) // checks return type from preincrement
);
template
using ForwardIterator = DefineConcept(
models>(), // ForwardIterator models Iterator
ref()++, // and provides post-increment
*ref()++ // and dereferencing a post-increment expression
);
template
using BidirectionalIterator = DefineConcept(
models>(), // BidirectionalIterator models ForwardIterator
has_type(--ref()), // and provides pre-decrement
convertible_to(ref()--), // and post-decrement
*ref()-- // and dereferencing a post-decrement
);
template
using diff_t = decltype(val() - val()); // alias for difference_type
template
using RandomAccessIterator = DefineConcept(
models>(), // RandomAccessIterator models BidirectionalIterator
has_type(ref() += val>()), // allows for arbitrary advancement
has_type(val() + val>()), // addition to difference_type
has_type(val>() + val()), // --- where order does not matter
has_type(ref() -= val>()), // arbitrary decrement modifying
has_type(val() - val>()), // and by unmodified with expression
val()[val>()] // and allows indexing with operator[]
);
```
Further examples and usage patterns will be described in the future
## License
This software is provided under a dual-license scheme (Boost License + BSD 3-clause).
The Boost License is use for relevant code from `ericneibler/range-v3` while the BSD 3-clause further specifies additional constraints on distribution, private use, and sublicensing.