https://github.com/pfultz2/pythy
Having it all now: Pythy syntax for C++11
https://github.com/pfultz2/pythy
Last synced: about 1 year ago
JSON representation
Having it all now: Pythy syntax for C++11
- Host: GitHub
- URL: https://github.com/pfultz2/pythy
- Owner: pfultz2
- Created: 2012-08-28T21:02:07.000Z (over 13 years ago)
- Default Branch: master
- Last Pushed: 2012-10-23T23:10:22.000Z (over 13 years ago)
- Last Synced: 2025-03-26T07:11:20.030Z (about 1 year ago)
- Language: C
- Size: 1.24 MB
- Stars: 23
- Watchers: 7
- Forks: 2
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
Pythy
=====
Having it all now: Pythy syntax for C++11.
Overview
--------
In a [blog post](http://cpp-next.com/archive/2011/11/having-it-all-pythy-syntax/), David Abrahams discussed an improved function syntax based around polymorphic lambdas:
```c++
[]min(x, y)
{ return x < y ? x : y; }
```
The pythy library implements this in C++11 using a macro like this:
```c++
PYTHY(min, x, y)
( return x < y ? x : y; )
```
Internally, it uses references for each of the parameters. To make each parameter const, the const keyword can be written:
```c++
PYTHY(min, const x, const y)
( return x < y ? x : y; )
```
If mutablility needs to be forced, the `mutable` keyword can be used:
```c++
PYTHY(add, mutable x, y)
(
x += y;
)
```
References can't be used, since a reference is already being used internally.
By default, pythy functions decay their return value, just like lambdas; so they always return by value, However, the `pythy::ref` function can be used to return a reference:
```c++
PYTHY(first, r)
(
return pythy::ref(*(begin(r)));
)
```
This macro is much more powerful than using the simple `RETURNS` macro, like below:
```c++
#define RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); }
template
auto min(T x, U y) RETURNS(x < y ? x : y)
```
For example, a multi-statement function can be written:
```c++
PYTHY(first, r)
(
if (r.empty()) throw "The range is empty";
return pythy::ref(*(begin(r)));
)
```
Or a function that returns lambda can be written:
```c++
PYTHY(equal_to, x)
(
return [=](decltype(x) y) { return x == y; }
)
```
Which can not be done using the `RETURNS` macro.
Implementation
--------------
This is implemented using a templated lambda. Lambdas can't be templated locally(and neither can classes), but we can make a lambda depend on a template parameter. So, if we define a lambda inside a templated class, like this:
```c++
template
struct min_t
{
constexpr static auto f = [](T0 x, T1 y){ return x < y ? x : y; };
};
```
This won't work, because a lambda closure(even if its non-capturing) is not a constexpr. However, using a trick(as suggested by Richard Smith from clang) we can initialize it as a null pointer:
```c++
template
typename std::remove_reference::type *addr(T &&t)
{
return &t;
}
template
struct min_t
{
constexpr static auto *f = false ? addr([](T0 x, T1 y){ return x < y ? x : y; }) : nullptr;
};
```
Then when we want to call our function, we can do this:
```c++
template
auto min(T0 x, T1 x) RETURNS((*min_t::f)(x, y))
```
It appears that we are derefencing a null pointer. Remember in C++ when dereferencing a null pointer, undefined behavior occurs when there is an lvalue-to-rvalue conversion. However, since a non-capturing lambda closure is almost always implemented as an object with no members, undefined behavior never occurs, since it won't access any of its members. Its highly unlikely that a non-capturing lambda closure could be implemented another way since it must be convertible to a function pointer. But the library does statically assert that the closure object is empty to avoid any possible undefined behavior.
Requirements
------------
This requires a compiler that supports `auto`, `constexpr` and lambdas. It also relies on boost. For some compilers the `-DBOOST_PP_VARIADICS=1` must be passed into the compiler.