2015-09-08 7 views
11

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

E.g.

// 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 мог работать (как в этом вопросе: Relying on ADL for std::begin() and std::end()?).

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

+0

ADL должен сделать это, что usings не требуется – Creris

+0

'using' связан области. –

+2

@Creris Это необходимо, если вы хотите, чтобы также работали массивы C-стиля. – Shoe

ответ

8

Поместите используя декларацию в отдельном пространстве имен:

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

+1

Если вы используете 'adl_begin' в теле, вы, вероятно, захотите его определить :) –

+0

@ T.C. * (или используйте помощника только в необоснованном контексте) *, вы правы, спасибо –

+0

'template using adl_begin = decltype (adl_helper :: adl_begin (std :: declval ()));' обязательно; затем 'template adl_begin make_custom_range (Container & c)'. Или, по крайней мере, «используя adl_helper :: adl_begin', чтобы вытащить его из внутреннего пространства имен. – Yakk

3

Выбросьте все в другое пространство имен и положить 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>())); 

В C++ 14, вам не нужны возвращаемые типы трейлинга, но также будет необходимо сделать то же самое для cbegin и cend. При том, что вам не нужно помнить, чтобы иметь using S когда-либо снова и просто использовать 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)); 
} 
+1

Мне не нравится 'C &' в 'adl_begin_t'; если они хотят контейнер lvalue, не должны ли они его просить? 'C &&' возможно (что помогает с сырыми типами массивов, если я правильно помню). – Yakk

+0

@Yakk Это работает как с массивными массивами, но я предполагаю, что запрещает контейнеры rvalue. Итак, конечно, я могу изменить на 'declval ()'. – Barry