template<typename Duck>
void talk(const Duck& duck)
{
duck.quack();
}
talk(10); ???
template<typename T>
T twice(const T& value)
{
return value * 2;
}
template<typename...>
using void_t = void;
template<typename T>
struct twiceable :
std::false_type
{};
template<typename T>
struct twiceable<T, void_t<decltype(std::declval<T>() * 2)>> :
std::true_type
{};
template<typename T,
typename = typename std::enable_if<
twiceable<T>::value
>::type>
T twice(const T& value)
{
return value * 2;
}
int i = twice(2);
template<typename T>
concept bool Type()
{
return true;
}
template<typename T>
concept bool Type = true;
template<typename T>
concept bool A = requires(T a)
{
...
};
template<typename T, typename U>
concept bool A = requires(T a, const U& b)
{
...
};
template<typename... Ts>
concept bool C = requires(Ts... ts)
{
...
};
"Sandbox" donde pedir valores con los que poder trabajar. Sustituye a std::declval<T>()
template<typename A, typename B = A>
concept bool Addable = requires(const A& a, const B& b)
{
a + b; // a + b es válido
// (existe operator+(A,B))
{a + b} -> int; // a + b es válido
// y devuelve int
{a + b} -> Addable; // a + b es válido
// y devuelve tipo que satisface Addable
};
template<typename T>
concept bool Iterable = requires()
{
typename T::iterator; // T tiene tipo miembro "iterator"
typename std::iterator_traits<T>; // Instancia de std::iterator_traits es válida
requires Iterator<typename T::iterator>; // T::iterator satisface el concepto "Iterator"
};
template<typename Map, typename Key>
auto search(const Map& map, const Key& key)
{
// it es de un tipo que satisface "Iterator"
Iterator it = map.find(key);
...
}
template<typename R, typename F>
requires Iterable<R> && Invokable<F, typename R::value_type>
void foreach(const R& range, F function)
{
for(const auto& e : range)
function(e);
}
template<typename A, typename B>
requires requires(A a, B b) { a + b; }
auto add(const A& a, const B& b)
{
return a + b;
}
template<typename T>
concept bool StreamableOut = requires(std::ostream& os, const T& value)
{
{ os << value } -> std::ostream&;
}
namespace boost
{
std::string lexical_cast(const StreamableOut& value)
{
std::ostringstream os;
os << value;
return os.str();
}
}
template<typename T>
concept bool DefaultConstructible = std::is_default_constructible<T>::value;
template<typename T, typename Alloc>
concept bool Allocator = is_instance_of<Alloc, T>::value &&
requires(const Alloc& alloc)
{
alloc.allocate(1);
...
}
template<DefaultConstructible T, Allocator<T> Alloc>
class vector
{
...
};
template<typename F, typename... Args>
concept bool Invokable = requires(F f, Args... args)
{
f(args...);
}
Invokable{F, Args...}
auto invoke(F f, Args&&... args)
{
return f(std::forward<Args>(args)...);
}
template<typename It>
concept bool Iterator = requires(It lvalue)
{
requires CopyConstructible<It>;
requires CopyAssignable<It>;
requires Destructible<It>;
requires Swappable<It>;
*lvalue;
{++lvalue} -> It&
};
template<typename It>
concept bool ForwardIterator = requires(It i)
{
requires InputIterator<It>;
requires DefaultConstructible<It>;
requires crab::Switch()
.Case(OutputIterator<It, detail::value_type<It>>)
.Then(Same<detail::value_type<It>&, detail::reference<It>>)
.Default()
.Then(Same<const detail::value_type<It>&, detail::reference<It>>)
();
{i++} -> It;
{*i++} -> detail::reference<It>;
};