An open API service indexing awesome lists of open source software.

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

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.