Skip to content

Instantly share code, notes, and snippets.

@vdaghan
Created June 1, 2022 20:00
Show Gist options
  • Save vdaghan/fb283e95e08b4842b398e153bb1f1d39 to your computer and use it in GitHub Desktop.
Save vdaghan/fb283e95e08b4842b398e153bb1f1d39 to your computer and use it in GitHub Desktop.
Concept Examples
/*
These are some concepts I had to create myself for my projects.
There may be shorter ways or more elegant ways to do these, yet I could not find them myself.
If you have any suggestions, please feel free to comment.
PS: I'll add tests for all of these concepts, eventually.
PPS: You can copy and paste this file as_is to Compiler Explorer (https://godbolt.org/) to play with.
Just make sure that you are compiling with a C++20-compliant compiler, with appropriate flags (/std:c++20 for MSVC, --std=c++20 for gcc).
*/
#include <concepts>
#include <iostream>
#include <functional>
#include <list>
#include <type_traits>
#include <vector>
template <typename F> concept CallableVoid = requires (F f) { f(); };
template <typename F, typename... Args> concept CallableWith = std::invocable<F, Args...>;
//TODO: Does not work when user can't specialise for argument type.
template <typename F, typename... Args> concept Callable = CallableWith<F, Args...> || CallableVoid<F>;
//TODO: Assumes the single argument of G can be {}-constructible. It shouldn't.
template <typename F, typename G> concept Composable = requires(F f, G g) {
requires std::invocable<F, decltype(g({}))>;
};
template <typename F, typename T> concept Returns = requires(F f, T t) {
{f({})} -> std::same_as<T>;
};
template <typename T> concept Container = std::ranges::range<T>;
template <typename T> using TypeOfElements = std::ranges::range_value_t<T>;
template <typename T, typename... Args> concept ContainerOfCallables = Container<T> && Callable<TypeOfElements<T>, Args...>;
template <typename T> concept IsVector = requires (T t, T::value_type v) {
//requires std::same_as<T, std::vector<decltype(v)>>; //< Alternative
requires std::same_as<T, std::vector<typename T::value_type>>;
};
//template <typename T> concept IsVector = std::same_as<T, std::vector<typename T::value_type>>; //< Alternative
// Dirty little macro for tests below
#define CHECK(...) std::cout << #__VA_ARGS__ << ": " << ##__VA_ARGS__ << std::endl;
int main(void) {
std::cout << std::boolalpha;
CHECK(IsVector<std::vector<int>>)
CHECK(IsVector<std::vector<std::vector<int>>>)
CHECK(IsVector<std::vector<std::list<int>>>)
CHECK(IsVector<std::list<std::vector<int>>>)
CHECK(IsVector<std::list<int>>)
CHECK(IsVector<int>)
using F_Void_Int = std::function<int(void)>;
using F_Int_Void = std::function<void(int)>;
auto void_double_Lambda = []() -> double {
return 0.0;
};
std::function<double(void)> void_double_Lambda_as_stdfunction = []() -> double {
return 0.0;
};
auto double_double_Lambda = [](double x) -> double {
return x*x;
};
CHECK(CallableVoid<F_Void_Int>)
CHECK(CallableVoid<F_Int_Void>)
CHECK(CallableVoid<decltype(void_double_Lambda)>)
CHECK(CallableVoid<decltype(void_double_Lambda_as_stdfunction)>)
CHECK(Callable<F_Void_Int>)
CHECK(Callable<F_Int_Void>)
using F_Int_Int = std::function<int(int)>;
using F_Int_String = std::function<std::string(int)>;
CHECK(Composable<F_Int_Int, F_Int_Int>)
CHECK(Composable<F_Int_String, F_Int_Int>)
CHECK(Composable<F_Int_Int, F_Int_String>)
using F_Int_VectorOfInt = std::function<std::vector<int>(int)>;
CHECK(Returns<F_Int_Int, int>)
CHECK(Returns<F_Int_String, std::string>)
CHECK(Returns<F_Int_VectorOfInt, int>)
std::cout << std::endl;
}
/* Returns:
IsVector<std::vector<int>>: true
IsVector<std::vector<std::vector<int>>>: true
IsVector<std::vector<std::list<int>>>: true
IsVector<std::list<std::vector<int>>>: false
IsVector<std::list<int>>: false
IsVector<int>: false
CallableVoid<F_Void_Int>: true
CallableVoid<F_Int_Void>: false
CallableVoid<decltype(void_double_Lambda)>: true
CallableVoid<decltype(void_double_Lambda_as_stdfunction)>: true
Callable<F_Void_Int>: true
Callable<F_Int_Void>: false
Composable<F_Int_Int, F_Int_Int>: true
Composable<F_Int_String, F_Int_Int>: true
Composable<F_Int_Int, F_Int_String>: false
Returns<F_Int_Int, int>: true
Returns<F_Int_String, std::string>: true
Returns<F_Int_VectorOfInt, int>: false
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment