Skip to content

Instantly share code, notes, and snippets.

@pfultz2
Created February 1, 2015 05:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfultz2/ac74129e73393f798e41 to your computer and use it in GitHub Desktop.
Save pfultz2/ac74129e73393f798e41 to your computer and use it in GitHub Desktop.
Transporting substitution failures for "advance" function
#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