How to use using-declarations in constraint

208 Views Asked by At

Is there an alternative to have some using-declarations in concept/constraint? Something like:

template <typename T>
concept has_begin_v0 = requires (T t)
{
    using std::begin; // KO
    begin(t);
    /*..*/
};

The possible ways I have found are:

  • use intermediate namespace

    namespace detail
    {
    using std::begin;
    template <typename T>
    concept has_begin_v1 = requires (T t)
    {
        begin(t);
    };
    }
    using detail::has_begin_v1;
    

    Introduces extra namespace :-(

  • using SFINAEd lambda:

    template <typename T>
    concept has_begin_v2 = requires (T t)
    {
        [](){
            using std::begin;
            return [](auto&& inner) -> std::void_t<decltype(begin(inner))> {};
        }()(t);
    };
    

    Not a fine syntax.

  • use "disjunction" of qualified call and adl call:

    template <typename T>
    concept has_std_begin = requires (T t)
    {
        std::begin(t);
    };
    
    template <typename T>
    concept has_adl_begin = requires (T t)
    {
        begin(t);
    };
    
    template <typename T>
    concept has_begin_v3 = has_std_begin<T> || has_adl_begin<T>;
    

    The nicer IMO, but seems not to scale nor allow to go further (is begin(t) comparable with end(t)?).

Demo

1

There are 1 best solutions below

0
On

You should generally avoid having to do the using std::begin trick. Since you're already operating in C++20, you can use the ranges customization point object std::ranges::begin. It does the ADL gymnastics you need on a direct call, so you don't need using std::begin.