Trailing return types and fallback for Koenig lookup

79 Views Asked by At

Most of the time, the C++17 inferred return type of a simple member function can be easily transformed to a C++11 trailing return type.

For example, the member function in

template<typename T>
struct X
{
    T a;
    auto f() { return frob(a); }
};

becomes

auto f() -> decltype(frob(a)) { return frob(a); }

Considering that using namespace is not permitted at top-level scope within a class body, how do you write a trailing return type for the following?

namespace widget
{
    template<typename S>
    int froz(S&&);
}

template<typename T>
struct Y
{
    T b;
    auto g() { using namespace widget; return froz(b); }
};

(For example, the usage of argument-dependent lookup with a fallback is very common when calling std::swap, std::begin, std::end)

template<typename T>
struct Z
{
    T container;
    auto h() { using namespace std; return begin(container); }
};
2

There are 2 best solutions below

3
Aykhan Hagverdili On

How about:

template<typename T>
struct Z
{
    T container;
    auto h() -> decltype(
        [] 
        {
            Z<T>* z;
            using namespace std; return begin(z->container);
        }()

    ) { using namespace std; return begin(container); }
};
4
Ben Voigt On

Here's the nicest workaround I have found, introducing a helper namespace to host the using namespace as closely as possible:

namespace impl
{
    using namespace std;

    template<typename T>
    struct Z
    {
        T container;
        auto h() -> decltype(begin(container)) { return begin(container); }
    };
}
using impl::Z;

To not affect the entire class, it could be use to make Ayxan's idea of using decltype on a helper function work in C++11:

namespace impl
{
    using namespace std;

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

template<typename T>
struct Z
{
    T container;
    auto h() -> decltype(impl::begin(container)) { using namespace std; return begin(container); }
};