Skip to content

Instantly share code, notes, and snippets.

@Redchards
Last active December 17, 2015 18:58
Show Gist options
  • Select an option

  • Save Redchards/22e74b4fb4134e7159fb to your computer and use it in GitHub Desktop.

Select an option

Save Redchards/22e74b4fb4134e7159fb to your computer and use it in GitHub Desktop.
A very simple implementation of "static_if" in C++14, implemented in roughly 30min, inspired by the n3329 working draft specification.
// Inspired by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3329.pdf
// Unfortunatly, there is not way to implement the most interesting feature right now : the static if inside classes.
// I didn't find a way to do this without ugly macro hacks, so we need to deal with it ...
// Oh, and special mention to SuperV1234 (https://github.com/SuperV1234) who did this far before me, with roughly the same implementation,
// a friend pointed this out after I finished implenting it (mine is slightly simpler though).
#include <iostream>
#include <type_traits>
namespace details
{
using std::declval;
template<class ... Args>
using void_t = void;
template<class T, class = void>
struct is_callable : std::false_type
{};
template<class T>
struct is_callable<T, void_t<decltype(declval<T>()())>> : std::true_type
{};
template<class Func>
struct static_if_result
{
static_assert(is_callable<Func>::value,
"static_if require branch bodies to be of callable type");
template<class F>
constexpr static_if_result& then_(F&&){ return *this; }
template<class F>
constexpr static_if_result& else_(F&&){ return *this; }
template<class F>
constexpr static_if_result& else_if_(F&&){ return *this; }
template<class ... Args>
auto operator()(Args&& ... args) noexcept(noexcept(declval<Func>()()))
{
return branch_execution(std::forward<Args>(args)...);
}
Func branch_execution;
};
template<bool T>
struct static_if_statement;
template<>
struct static_if_statement<true>
{
template<class F>
constexpr static_if_result<F> then_(F&& f){ return {std::forward<F>(f)}; }
template<class F>
constexpr static_if_statement& else_(F&&){ return *this; }
template<class F>
constexpr static_if_statement& else_if_(F&&){ return *this; }
};
template<>
struct static_if_statement<false>
{
template<class F>
constexpr static_if_statement& then_(F&&){ return *this; }
template<class F>
constexpr static_if_result<F> else_(F&& f){ return {std::forward<F>(f)}; }
template<class TPredicate>
constexpr auto else_if_(TPredicate)
{
return static_if_statement<TPredicate::value>{};
}
};
}
template<class TPredicate>
constexpr auto static_if(TPredicate)
{
return details::static_if_statement<TPredicate::value>{};
}
// Very simple example
struct foo;
struct bar;
struct other;
template<class T>
void static_if_tst()
{
static_if(std::is_same<T, foo>{}).then_(
[](){
std::cout << "I'm a foo !" << std::endl;
}
).else_if_(std::is_same<T, bar>{}).then_(
[](){
std::cout << "This is a guy who walks in a bar ..." << std::endl;
}
).else_(
[](){
std::cout << "Nothing to say right now." << std::endl;
}
)();
}
int main()
{
static_if_tst<foo>();
static_if_tst<bar>();
static_if_tst<other>();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment