Skip to content

Instantly share code, notes, and snippets.

@remyroez
Last active November 21, 2016 06:58
Show Gist options
  • Save remyroez/dcca3fcbdba0f8a907a48f884bf7fbb3 to your computer and use it in GitHub Desktop.
Save remyroez/dcca3fcbdba0f8a907a48f884bf7fbb3 to your computer and use it in GitHub Desktop.
SFINAE コンセプト
#include <iostream>
#include <type_traits>
#if (__cplusplus > 201402L)
using std::void_t;
using std::bool_constant;
using std::negation;
using std::conjunction;
using std::conjunction_v;
using std::disjunction;
using std::disjunction_v;
#else
template <typename...> using void_t = void;
template <bool B>
using bool_constant = std::integral_constant<bool, B>;
template <class T>
using negation = bool_constant<!T::value>;
template <class...>
struct conjunction : std::true_type {};
template <class T>
struct conjunction<T> : T {};
template <class T, class... Args>
struct conjunction<T, Args...> : std::conditional_t<T::value, conjunction<Args...>, T> {};
template <class... Args>
constexpr conjunction_v = conjunction<Args>::value;
template <class...>
struct disjunction : std::false_type {};
template <class T>
struct disjunction<T> : T {};
template <class T, class... Args>
struct disjunction<T, Args...> : std::conditional_t<T::value, T, disjunction<Args...>> {};
template <class... Args>
constexpr disjunction_v = disjunction<Args>::value;
#endif
// impl ----------
template <class T>
struct concept : std::enable_if<T::value, std::nullptr_t> {};
template <class T>
using concept_t = typename concept<T>::type;
template <typename ...Args>
using require_concepts = concept<conjunction<Args...>>;
template <typename ...Args>
using require_concepts_t = typename require_concepts<Args...>::type;
template <typename ...Args>
using disallow_concepts = require_concepts<negation<Args>...>;
template <typename ...Args>
using disallow_concepts_t = typename disallow_concepts<Args...>::type;
template <typename ...Args>
using either_concepts = concept<disjunction<Args...>>;
template <typename ...Args>
using either_concepts_t = typename either_concepts<Args...>::type;
#define requires(...) require_concepts_t<__VA_ARGS__> = nullptr
#define disallow(...) disallow_concepts_t<__VA_ARGS__> = nullptr
#define either(...) either_concepts_t<__VA_ARGS__> = nullptr
// usage ----------
template <class, class = void_t<>>
struct Fooable : std::false_type {};
template <class T>
struct Fooable<T, void_t<either_concepts_t<
std::is_enum<T>,
std::is_integral<T>,
std::is_floating_point<T>>>> : std::true_type {};
template <class T, requires(std::is_enum<T>)>
auto foo(T a) { return static_cast<int>(a); }
template <class T, requires(std::is_integral<T>)>
auto foo(T a) { return a / 2; }
template <class T, requires(std::is_floating_point<T>)>
auto foo(T a) { return a * 2; }
template <class T, disallow(Fooable<T>)>
auto foo(T) {
static_assert(Fooable<T>::value, "invalid parameter!");
return 0;
}
template <class T, either(std::is_integral<T>, std::is_floating_point<T>)>
auto bar(T a) { return a * 100; }
template <class T, disallow(std::is_integral<T>, std::is_floating_point<T>)>
auto bar(T) {
static_assert(disjunction<std::is_integral<T>, std::is_floating_point<T>>::value, "invalid parameter!");
return 0;
}
enum class baz : int { hoge = 123, fuga = 456, moge = 789 };
int main()
{
std::cout << foo(10) << std::endl;
std::cout << foo(100.0f) << std::endl;
std::cout << foo(baz::fuga) << std::endl;
//std::cout << foo("cat") << std::endl;
std::cout << bar(100) << std::endl;
std::cout << bar(200.0f) << std::endl;
//std::cout << bar("dog") << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment