Created
February 1, 2015 05:37
-
-
Save pfultz2/ac74129e73393f798e41 to your computer and use it in GitHub Desktop.
Transporting substitution failures for "advance" function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <list> | |
#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__), int>::type = 0 | |
#define REQUIRE_OF(...) template<class Id> using apply = typename std::enable_if<(Id()(__VA_ARGS__)), int>::type | |
template<class T> | |
struct always_void | |
{ | |
typedef void type; | |
}; | |
template<class Concept, class Enable=void> | |
struct models | |
: std::false_type | |
{}; | |
template<class Concept, class... Ts> | |
struct models<Concept(Ts...), typename always_void< | |
decltype(std::declval<Concept>().requires_(std::declval<Ts>()...)) | |
>::type> | |
: std::true_type | |
{}; | |
struct Callable | |
{ | |
template<class F, class... Ts> | |
auto requires_(F&& f, Ts&&... xs) -> decltype( | |
f(std::forward<Ts>(xs)...) | |
); | |
}; | |
struct identity | |
{ | |
template<class T> | |
constexpr T operator()(T&& x) const | |
{ | |
return std::forward<T>(x); | |
} | |
}; | |
template<class F, class=void> | |
struct get_failure | |
{ | |
template<class... Ts> | |
struct of | |
{ | |
template<class Id> | |
using apply = decltype(Id()(std::declval<F>())(std::declval<Ts>()...)); | |
}; | |
}; | |
template<class F> | |
struct get_failure<F, typename always_void< | |
typename F::failure | |
>::type> | |
: F::failure | |
{}; | |
template<class Failure, class... Ts> | |
struct apply_failure | |
: Failure::template of<Ts...> | |
{}; | |
template<class Id, class Failure, class... Ts> | |
using enabled = typename apply_failure<Failure, Ts...>::template apply<Id>; | |
template<class F, class Failure> | |
struct reveal_failure | |
{ | |
template<class... Ts, class Id=identity, class=enabled<Id, Failure, Ts...>, REQUIRES(Id()(false))> | |
auto operator()(Ts&&... xs) -> decltype(F()(std::forward<Ts>(xs)...)) | |
{ | |
return F()(std::forward<Ts>(xs)...); | |
} | |
}; | |
template<class F, class Failure=get_failure<F>, class=void> | |
struct traverse_failure | |
: reveal_failure<F, Failure> | |
{}; | |
template<class F, class Failure> | |
struct traverse_failure<F, Failure, typename always_void< | |
typename Failure::children | |
>::type> | |
: Failure::children::template apply<F> | |
{}; | |
template<class Failure, class... Failures> | |
struct failures | |
{ | |
template<class F> | |
struct apply | |
: traverse_failure<F, Failure>, failures<Failures...>::template apply<F> | |
{ | |
using traverse_failure<F, Failure>::operator(); | |
using failures<Failures...>::template apply<F>::operator(); | |
}; | |
}; | |
template<class Failure> | |
struct failures<Failure> | |
{ | |
template<class F> | |
struct apply | |
: traverse_failure<F, Failure> | |
{}; | |
}; | |
template<class F> | |
struct reveal | |
: traverse_failure<F>, F | |
{ | |
using traverse_failure<F>::operator(); | |
using F::operator(); | |
}; | |
template<class F1, class F2> | |
struct basic_conditional | |
{ | |
struct failure | |
{ | |
using children = failures<get_failure<F1>, get_failure<F2>>; | |
}; | |
template<class... Ts> | |
auto operator()(Ts&&... xs) -> decltype(F1()(std::forward<Ts>(xs)...)) | |
{ | |
return F1()(std::forward<Ts>(xs)...); | |
} | |
template<class... Ts, REQUIRES(!models<Callable(F1, Ts&&...)>())> | |
auto operator()(Ts&&... xs) -> decltype(F2()(std::forward<Ts>(xs)...)) | |
{ | |
return F2()(std::forward<Ts>(xs)...); | |
} | |
}; | |
template<class F, class... Fs> | |
struct conditional : basic_conditional<F, conditional<Fs...>> | |
{}; | |
template<class F> | |
struct conditional<F> : F | |
{}; | |
struct Incrementable | |
{ | |
template<class T> | |
auto requires_(T&& x) -> decltype(++x); | |
}; | |
struct Decrementable | |
{ | |
template<class T> | |
auto requires_(T&& x) -> decltype(--x); | |
}; | |
struct Advanceable | |
{ | |
template<class T, class I> | |
auto requires_(T&& x, I&& i) -> decltype(x += i); | |
}; | |
struct advance_advanceable | |
{ | |
struct failure | |
{ | |
template<class...> | |
struct of; | |
template<class Iterator, class T> | |
struct of<Iterator, T> | |
{ | |
REQUIRE_OF(models<Advanceable(Iterator, int)>()); | |
}; | |
}; | |
template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())> | |
void operator()(Iterator& it, int n) const | |
{ | |
it += n; | |
} | |
}; | |
struct advance_decrementable | |
{ | |
struct failure | |
{ | |
template<class...> | |
struct of; | |
template<class Iterator, class T> | |
struct of<Iterator, T> | |
{ | |
REQUIRE_OF(models<Decrementable(Iterator)>()); | |
}; | |
}; | |
template<class Iterator, REQUIRES(models<Decrementable(Iterator)>())> | |
void operator()(Iterator& it, int n) const | |
{ | |
if (n > 0) while (n--) ++it; | |
else | |
{ | |
n *= -1; | |
while (n--) --it; | |
} | |
} | |
}; | |
struct advance_incrementable | |
{ | |
struct failure | |
{ | |
template<class...> | |
struct of; | |
template<class Iterator, class T> | |
struct of<Iterator, T> | |
{ | |
REQUIRE_OF(models<Incrementable(Iterator)>()); | |
}; | |
}; | |
template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())> | |
void operator()(Iterator& it, int n) const | |
{ | |
while (n--) ++it; | |
} | |
}; | |
static reveal<conditional<advance_advanceable, advance_decrementable, advance_incrementable>> advance = {}; | |
struct foo {}; | |
int main() | |
{ | |
foo f; | |
advance(f, 1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment