问题 将using语句应用于函数的返回类型,而不应用于整个命名空间


我正在尝试创建一个接受底层容器的函数,并根据对元素进行一些处理的自定义迭代器返回一个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被导入到声明我的函数的整个命名空间。我不喜欢在decltype中明确使用std :: begin,以便ADL可以工作(如下所示: 依赖于ADL for std :: begin()和std :: end()?)。

我想在C ++ 14中,我可以在这里使用自动返回类型。有C ++ 11解决方案吗?有没有办法让返回类型看到using声明而不将它暴露给整个命名空间?


3574
2017-09-08 18:13


起源

ADL应该确保不需要使用 - Creris
using 受范围约束。 - Captain Obvlious
@Creris如果你想要C风格的数组也可以使用它 - Shoe
将演绎工具放入详细信息命名空间。 - T.C.
@Creris是的,但没有那些 usings,不 begin 和 end 将使用ADL为C风格的数组找到函数。 - Shoe


答案:


将using声明放在一个单独的命名空间中:

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


8
2017-09-08 18:30



如果你正在使用 adl_begin 在体内,你可能想要定义它:) - T.C.
@ T.C。 (或仅在未评估的上下文中使用帮助程序),你说得对,谢谢 - Piotr Skotnicki
template<class T>using adl_begin=decltype(adl_helper::adl_begin(std::declval<T>())); 一定;然后 template<class Container> adl_begin<Container&> make_custom_range(Container& c)。或者至少 using adl_helper::adl_begin 将其拉出内部命名空间。 - Yakk - Adam Nevraumont


将所有内容放入另一个命名空间并放入您的 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再一次,只是使用 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));
}

3
2017-09-08 18:43



我不喜欢 C& 在 adl_begin_t;如果他们想要左值容器,他们不应该要求它吗? C&& 也许(如果我没记错的话,这有助于原始数组类型)。 - Yakk - Adam Nevraumont
@Yakk这与原始数组一样,但我猜禁止rvalue容器。所以,当然,我可以改为 declval<C>()。 - Barry