Skip to content

Instantly share code, notes, and snippets.

@isc30
Last active April 3, 2019 15:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isc30/fcd53dbb00526a70e5c27a754488480e to your computer and use it in GitHub Desktop.
Save isc30/fcd53dbb00526a70e5c27a754488480e to your computer and use it in GitHub Desktop.
#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