using std::begin;
template <typename ContainerTy>
-auto adl_begin(ContainerTy &&container)
- -> decltype(begin(std::forward<ContainerTy>(container))) {
+decltype(auto) adl_begin(ContainerTy &&container) {
return begin(std::forward<ContainerTy>(container));
}
using std::end;
template <typename ContainerTy>
-auto adl_end(ContainerTy &&container)
- -> decltype(end(std::forward<ContainerTy>(container))) {
+decltype(auto) adl_end(ContainerTy &&container) {
return end(std::forward<ContainerTy>(container));
}
} // end namespace adl_detail
template <typename ContainerTy>
-auto adl_begin(ContainerTy &&container)
- -> decltype(adl_detail::adl_begin(std::forward<ContainerTy>(container))) {
+decltype(auto) adl_begin(ContainerTy &&container) {
return adl_detail::adl_begin(std::forward<ContainerTy>(container));
}
template <typename ContainerTy>
-auto adl_end(ContainerTy &&container)
- -> decltype(adl_detail::adl_end(std::forward<ContainerTy>(container))) {
+decltype(auto) adl_end(ContainerTy &&container) {
return adl_detail::adl_end(std::forward<ContainerTy>(container));
}
/// Return a range covering \p RangeOrContainer with the first N elements
/// excluded.
-template <typename T>
-auto drop_begin(T &&RangeOrContainer, size_t N) ->
- iterator_range<decltype(adl_begin(RangeOrContainer))> {
+template <typename T> auto drop_begin(T &&RangeOrContainer, size_t N) {
return make_range(std::next(adl_begin(RangeOrContainer), N),
adl_end(RangeOrContainer));
}
}
template <class ContainerTy, class FuncTy>
-auto map_range(ContainerTy &&C, FuncTy F)
- -> decltype(make_range(map_iterator(C.begin(), F),
- map_iterator(C.end(), F))) {
+auto map_range(ContainerTy &&C, FuncTy F) {
return make_range(map_iterator(C.begin(), F), map_iterator(C.end(), F));
}
// Returns an iterator_range over the given container which iterates in reverse.
// Note that the container must have rbegin()/rend() methods for this to work.
template <typename ContainerTy>
-auto reverse(ContainerTy &&C,
- typename std::enable_if<has_rbegin<ContainerTy>::value>::type * =
- nullptr) -> decltype(make_range(C.rbegin(), C.rend())) {
+auto reverse(
+ ContainerTy &&C,
+ typename std::enable_if<has_rbegin<ContainerTy>::value>::type * = nullptr) {
return make_range(C.rbegin(), C.rend());
}
// Note that the container must have begin()/end() methods which return
// bidirectional iterators for this to work.
template <typename ContainerTy>
-auto reverse(
- ContainerTy &&C,
- typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * = nullptr)
- -> decltype(make_range(llvm::make_reverse_iterator(std::end(C)),
- llvm::make_reverse_iterator(std::begin(C)))) {
+auto reverse(ContainerTy &&C,
+ typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * =
+ nullptr) {
return make_range(llvm::make_reverse_iterator(std::end(C)),
llvm::make_reverse_iterator(std::begin(C)));
}
}
template <typename Iter>
-static auto deref_or_none(const Iter &I, const Iter &End)
- -> llvm::Optional<typename std::remove_const<
- typename std::remove_reference<decltype(*I)>::type>::type> {
+static auto deref_or_none(const Iter &I, const Iter &End) -> llvm::Optional<
+ std::remove_const_t<std::remove_reference_t<decltype(*I)>>> {
if (I == End)
return None;
return *I;
FuncTy func;
template <typename T>
- auto operator()(const T &lhs, const T &rhs) const
- -> decltype(func(lhs.first, rhs.first)) {
+ decltype(auto) operator()(const T &lhs, const T &rhs) const {
return func(lhs.first, rhs.first);
}
};
std::is_same<typename std::iterator_traits<decltype(
Range.begin())>::iterator_category,
std::random_access_iterator_tag>::value,
- void>::type * = nullptr)
- -> decltype(std::distance(Range.begin(), Range.end())) {
+ void>::type * = nullptr) {
return std::distance(Range.begin(), Range.end());
}
/// Provide wrappers to std::find which take ranges instead of having to pass
/// begin/end explicitly.
-template <typename R, typename T>
-auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range)) {
+template <typename R, typename T> auto find(R &&Range, const T &Val) {
return std::find(adl_begin(Range), adl_end(Range), Val);
}
/// Provide wrappers to std::find_if which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, typename UnaryPredicate>
-auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+auto find_if(R &&Range, UnaryPredicate P) {
return std::find_if(adl_begin(Range), adl_end(Range), P);
}
template <typename R, typename UnaryPredicate>
-auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+auto find_if_not(R &&Range, UnaryPredicate P) {
return std::find_if_not(adl_begin(Range), adl_end(Range), P);
}
/// Provide wrappers to std::remove_if which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename UnaryPredicate>
-auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+auto remove_if(R &&Range, UnaryPredicate P) {
return std::remove_if(adl_begin(Range), adl_end(Range), P);
}
/// Wrapper function around std::count to count the number of times an element
/// \p Element occurs in the given range \p Range.
-template <typename R, typename E>
-auto count(R &&Range, const E &Element) ->
- typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type {
+template <typename R, typename E> auto count(R &&Range, const E &Element) {
return std::count(adl_begin(Range), adl_end(Range), Element);
}
/// Wrapper function around std::count_if to count the number of times an
/// element satisfying a given predicate occurs in a range.
template <typename R, typename UnaryPredicate>
-auto count_if(R &&Range, UnaryPredicate P) ->
- typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type {
+auto count_if(R &&Range, UnaryPredicate P) {
return std::count_if(adl_begin(Range), adl_end(Range), P);
}
/// Provide wrappers to std::partition which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename UnaryPredicate>
-auto partition(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+auto partition(R &&Range, UnaryPredicate P) {
return std::partition(adl_begin(Range), adl_end(Range), P);
}
/// Provide wrappers to std::lower_bound which take ranges instead of having to
/// pass begin/end explicitly.
-template <typename R, typename T>
-auto lower_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) {
+template <typename R, typename T> auto lower_bound(R &&Range, T &&Value) {
return std::lower_bound(adl_begin(Range), adl_end(Range),
std::forward<T>(Value));
}
template <typename R, typename T, typename Compare>
-auto lower_bound(R &&Range, T &&Value, Compare C)
- -> decltype(adl_begin(Range)) {
+auto lower_bound(R &&Range, T &&Value, Compare C) {
return std::lower_bound(adl_begin(Range), adl_end(Range),
std::forward<T>(Value), C);
}
/// Provide wrappers to std::upper_bound which take ranges instead of having to
/// pass begin/end explicitly.
-template <typename R, typename T>
-auto upper_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) {
+template <typename R, typename T> auto upper_bound(R &&Range, T &&Value) {
return std::upper_bound(adl_begin(Range), adl_end(Range),
std::forward<T>(Value));
}
template <typename R, typename T, typename Compare>
-auto upper_bound(R &&Range, T &&Value, Compare C)
- -> decltype(adl_begin(Range)) {
+auto upper_bound(R &&Range, T &&Value, Compare C) {
return std::upper_bound(adl_begin(Range), adl_end(Range),
std::forward<T>(Value), C);
}
/// Requires that C is always true below some limit, and always false above it.
template <typename R, typename Predicate,
typename Val = decltype(*adl_begin(std::declval<R>()))>
-auto partition_point(R &&Range, Predicate P) -> decltype(adl_begin(Range)) {
+auto partition_point(R &&Range, Predicate P) {
return std::partition_point(adl_begin(Range), adl_end(Range), P);
}
// Could be further improved to cope with non-derivable functors and
// non-binary functors (should be a variadic template member function
// operator()).
- template <typename A, typename B>
- auto operator()(A &lhs, B &rhs) const -> decltype(func(*lhs, *rhs)) {
+ template <typename A, typename B> auto operator()(A &lhs, B &rhs) const {
assert(lhs);
assert(rhs);
return func(*lhs, *rhs);
namespace detail {
template <typename F, typename Tuple, std::size_t... I>
-auto apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>)
- -> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...)) {
+decltype(auto) apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
/// tuple variadically to f as if by calling f(a1, a2, ..., an) and
/// return the result.
template <typename F, typename Tuple>
-auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(
- std::forward<F>(f), std::forward<Tuple>(t),
- std::make_index_sequence<
- std::tuple_size<typename std::decay<Tuple>::type>::value>{})) {
+decltype(auto) apply_tuple(F &&f, Tuple &&t) {
using Indices = std::make_index_sequence<
std::tuple_size<typename std::decay<Tuple>::type>::value>;
/// Returns a raw pointer that represents the same address as the argument.
///
-/// The late bound return should be removed once we move to C++14 to better
-/// align with the C++20 declaration. Also, this implementation can be removed
-/// once we move to C++20 where it's defined as std::to_addres()
+/// This implementation can be removed once we move to C++20 where it's defined
+/// as std::to_addres().
///
/// The std::pointer_traits<>::to_address(p) variations of these overloads has
/// not been implemented.
-template <class Ptr> auto to_address(const Ptr &P) -> decltype(P.operator->()) {
- return P.operator->();
-}
+template <class Ptr> auto to_address(const Ptr &P) { return P.operator->(); }
template <class T> constexpr T *to_address(T *P) { return P; }
} // end namespace llvm