Применить с помощью оператора к типу возвращаемого значения функции без применения ко всему пространству имен

Я пытаюсь создать функцию, которая берет базовый контейнер, и возвращает boost:: iterator_range на основе пользовательского итератора, который выполняет некоторую обработку элементов.

например.

// The range class, templated on the underlying iterator type
template<class Iter> using CustomRange = boost::iterator_range<CustomIterator<Iter>>;

using std::begin;
template <class Container>
auto make_custom_range(Container& c) -> CustomRange<decltype(begin(c))> {
    using std::end;
    return make_custom_range_from_iterators(begin(c),end(c));
}

Работает код (с учетом соответствующих определений для CustomIterator и make_custom_range_from_iterators).

Меня беспокоит объявление using std::begin, которое, я думаю, приведет к тому, что std:: begin будет импортирован во все пространство имен, где объявлена ​​моя функция. Я предпочитаю не использовать std:: begin явно в decltype, чтобы ADL мог работать (как в этом вопросе: Опираясь на ADL для std:: begin() и std:: end ( )?).

Я думаю, что в С++ 14 я мог бы использовать здесь тип автоматического возврата. Есть ли решение С++ 11? Есть ли способ, чтобы возвращаемый тип отображался в объявлении using, не подвергая его всему пространству имен?

Ответ 1

Поместите объявление использования в отдельное пространство имен:

namespace adl_helper
{
    using std::begin;

    template <typename T>
    auto adl_begin(T&& t) -> decltype(begin(std::forward<T>(t)));  
}

template <class Container>
auto make_custom_range(Container& c)
    -> CustomRange<decltype(adl_helper::adl_begin(c))>
//                          ~~~~~~~~~~~~~~~~~~~~^
{
    using std::begin;
    using std::end;
    return make_custom_range_from_iterators(begin(c),end(c));
}

DEMO

Ответ 2

Бросьте все в другое пространство имен и разместите там using. Затем добавьте новых помощников в свое верхнее пространство имен:

namespace details {
    using std::begin;
    using std::end;

    template <typename C>
    auto adl_begin(C&& c) -> decltype(begin(std::forward<C>(c))) {
        return begin(std::forward<C>(c));
    }

    template <typename C>
    auto adl_end(C&& c) -> decltype(end(std::forward<C>(c))) {
        return end(std::forward<C>(c));
    }
}

using details::adl_begin;
using details::adl_end;

template <typename C>
using adl_begin_t = decltype(adl_begin(std::declval<C>()));

template <typename C>
using adl_end_t = decltype(adl_end(std::declval<C>()));

В С++ 14 вам не понадобятся типы возвращаемых возвратов, но также необходимо будет сделать то же самое для cbegin и cend. При этом вам не нужно помнить о том, чтобы снова иметь using и просто использовать методы adl_*:

template <class Container>
CustomRange<adl_begin_t<Container&>> make_custom_range(Container& c) {
    return make_custom_range_from_iterators(adl_begin(c), adl_end(c));
}