Last active
April 3, 2019 15:33
-
-
Save isc30/fcd53dbb00526a70e5c27a754488480e to your computer and use it in GitHub Desktop.
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 <type_traits> | |
#include <tuple> | |
namespace sfinae | |
{ | |
using success = std::true_type; | |
using fail = std::false_type; | |
template<typename T, typename... TChecks> | |
using resolve = T; | |
template<typename... TChecks> | |
using try_success = resolve<success, TChecks...>; | |
} | |
namespace lambda | |
{ | |
template<typename TCallable, typename... TArgs> | |
sfinae::try_success<std::invoke_result_t<TCallable, TArgs...>> is_callable(int); | |
template<typename TCallable, typename... TArgs> | |
sfinae::fail is_callable(...); | |
template<typename TCallable, typename... TArgs> | |
using is_callable_t = decltype(is_callable<TCallable, TArgs...>(int())); | |
} | |
template<typename TSuccess, typename TFail> | |
struct requirement : TSuccess, TFail | |
{ | |
constexpr requirement(const TSuccess& s, const TFail& f) | |
: TSuccess(s) | |
, TFail(f) | |
{} | |
using TSuccess::operator(); | |
using TFail::operator(); | |
using success_t = TSuccess; | |
}; | |
template<typename TSuccess, typename TFail> | |
constexpr requirement<TSuccess, TFail> make_requirement(const TSuccess& s, const TFail& f) | |
{ | |
return { s, f }; | |
} | |
template<typename T, typename TRequirement> | |
constexpr bool check_requirement(const TRequirement& requirement) | |
{ | |
return lambda::is_callable_t<typename TRequirement::success_t, T>::value; | |
} | |
template<typename T, typename TRequirement> | |
constexpr auto assert_requirement(const TRequirement& requirement) | |
{ | |
return lambda::is_callable_t<TRequirement, T>::value; | |
} | |
template<typename...> | |
struct force_false : std::false_type { }; | |
constexpr auto hasSize = make_requirement( | |
[](auto v) -> decltype(v.size()) { }, | |
[](auto&&... v) { static_assert(force_false<decltype(v)...>::value, "T has no method `T.size()`"); }); | |
static_assert(!check_requirement<int>(hasSize), "int"); | |
static_assert(check_requirement<std::string>(hasSize), "string"); | |
#define concept(name) struct name { static constexpr auto requirements = std::make_tuple( | |
#define end_concept ); }; | |
#define require(var, check, msg) make_requirement([](var) -> check { }, [](auto&&... v) { static_assert(force_false<decltype(v)...>::value, "Concept error: " msg); }) | |
template<typename TImpl> | |
struct Concept : TImpl | |
{ | |
template<typename T, typename... TTuple> | |
static constexpr bool check_requirements(const std::tuple<TTuple...>& tuple) | |
{ | |
return check_requirements<T>(std::index_sequence_for<TTuple...>()); | |
} | |
template<typename T, std::size_t... Indices> | |
static constexpr bool check_requirements(std::index_sequence<Indices...>) | |
{ | |
return std::conjunction_v<std::integral_constant<bool, check_requirement<T>(std::get<Indices>(TImpl::requirements))>...>; | |
} | |
template<typename T, typename... TTuple> | |
static constexpr auto assert_requirements(const std::tuple<TTuple...>& tuple) | |
{ | |
return assert_requirements<T>(std::index_sequence_for<TTuple...>()); | |
} | |
template<typename T, std::size_t... Indices> | |
static constexpr auto assert_requirements(std::index_sequence<Indices...>) | |
{ | |
return std::conjunction_v<std::integral_constant<bool, assert_requirement<T>(std::get<Indices>(TImpl::requirements))>...>; | |
} | |
template<typename T> | |
static constexpr bool valid() | |
{ | |
return check_requirements<T>(TImpl::requirements); | |
} | |
template<typename T> | |
static constexpr auto assert() | |
{ | |
return assert_requirements<T>(TImpl::requirements); | |
} | |
}; | |
concept(CWithSizeType) | |
require(auto v, typename decltype(v)::size_type, "required member 'T::size_type'") | |
end_concept | |
concept(CWithSize) | |
require(auto v, decltype(v.size()), "required method 'T.size()'"), | |
require(auto v, decltype(v.size()), "required method 'T.saaaize()'") | |
end_concept | |
static_assert(!Concept<CWithSize>::valid<int>(), "int"); | |
static_assert(Concept<CWithSize>::valid<std::string>(), "string"); | |
constexpr auto a0 = Concept<CWithSize>::assert<std::string>(); | |
//constexpr auto a1 = Concept<CWithSize>::assert<int>(); | |
template<typename T, typename... TConcept> | |
//using enable_concept = sfinae::resolve<T, std::enable_if<(Concept<TConcept>::template assert<T>() && ...)>>; | |
using enable_concept = sfinae::resolve<T, std::enable_if<std::conjunction_v<std::integral_constant<bool, Concept<TConcept>::template assert<T>()>...>>>; | |
template<typename T> | |
using WithSize = enable_concept<T, CWithSizeType, CWithSize>; | |
template<typename T> | |
void print_size(const WithSize<T>& v) | |
{ | |
std::cout << v.size(); | |
} | |
int maain() | |
{ | |
// print_size(123); | |
print_size(std::vector<int>()); | |
print_size(std::string("xd")); | |
//print_size(123123); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment