3

I have a function that looks more or less like this:

template<class C> auto f(C const& c) -> decltype(begin(c)){
    using std::begin;
    return begin(c);
}
  1. The body of the function exploits the "using and use" idiom and

  2. thanks to the decltype, will SFINAE if the return type is not valid.

However it is not perfect in general because I have no way to tell the decltype to have a using std declaration for begin.

template<class C> auto f(C const& c) -> decltype(std::begin(c))

would also be inconsistent, e.g. when decltype(c) and begin belongs to a different namespace.

Is there way around it?

Ideally, I want something like

template<class C> auto f(C const& c) -> decltype(using std::begin; begin(c))

I think a lambda could work in principle

template<class C> auto f(C const& c) -> decltype([&]{using std::begin; return begin(c)})

but lambdas are forbidden inside decltype.


In GCC there is an interesting language extension ("expression statements") that is promising, however it doesn't work outside the body of the function (same as lambdas are not allowed in unevaluated context). Otherwise it would be a solution.

template<class C> auto g(C const& c) 
->decltype(({using std::begin; begin(c);})){ // ...that doesn't work here
    return(({using std::begin; begin(c);})); // gcc extesion...
}
alfC
  • 14,261
  • 4
  • 67
  • 118

1 Answers1

5

You can delegate to an ADL enabled namespace

namespace detail
{
    using std::begin;
    template<class C> auto f(C const& c) -> decltype(begin(c)){
        return begin(c);
    }
}

template<class C> auto f(C const& c) -> decltype(detail::f(c)){
    return detail::f(c);
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 2
    Or just `using detail::f`. – n. m. could be an AI May 21 '18 at 21:08
  • @alfC Well, not *so* much more code, you'd probably place your `maybe_std_begin` in a `detail` or similar private namespace. So all you're achieving is omitting the trailing return type. That results in your version having `auto`'s return type deduction, while mine has `decltype`'s behavior, granted that shouldn't matter for something like `begin`, but it might if `f` calls some other function. – Praetorian May 21 '18 at 22:48
  • @alfC Yeah, now your version should behave the same. Anyway, you should accept your own answer if you prefer that version. – Praetorian May 22 '18 at 02:16
  • Test for SFINAE-friendliness https://wandbox.org/permlink/HqmmQupcQIN3N4ok – alfC May 22 '18 at 16:30
  • @alfC Can you please share the C++14 solution to the problem? – orLcount Jun 13 '21 at 20:06
  • 1
    @orLcount, sorry to disappoint you, I thought back then I found a solution but it was really garbage. So I deleted my answers in this thread. I am going to delete my comment. Here is a view of these (incorrect I think) answers. https://pasteboard.co/K6sS3oGp.png – alfC Jun 13 '21 at 20:14