How to Write an Adl-Enabled Trailing Return Type, or Noexcept Specification

How do I write an ADL-enabled trailing return type, or noexcept specification?

I think I would move it into a separate namespace

namespace tricks {
using std::swap;

template <typename T, typename U>
void swap(T &t, U &u) noexcept(noexcept(swap(t, u)));
}

template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
noexcept(noexcept(tricks::swap(std::declval<T>(), std::declval<T>())))
{
using std::swap;
swap(x.something_that_is_a_T, y.something_that_is_a_T);
}

Alternatively you can move the whole code up into tricks and delegate to there.

Determining return type of generic function

Use a separate namespace, where you can put the using clause. This prevents the namespace pollution, since the using clause only applies to that namespace. I would recommend naming it something unique, so you don't accidentally spread it around.

namespace transmog_detail
{
using std::abs;

template<class T>
auto transmogrify(T x) -> decltype(abs(x) + 2.0)
{
return abs(x) + 2.0;
}
}

// Then pull it into the current namespace, as recommended by @LucDanton.
using transmog_detail::transmogrify;

// Or if there is a reason, you can forward.
// template<class T>
// auto transmogrify(T x)
// -> decltype(transmog_detail::transmogrify(x))
// {
// return transmog_detail::transmogrify(x);
// }

`decltype` and mixing ADL-lookup with non-ADL-lookup

You can use a detail namespace and some wrapping:

namespace detail {
using std::sin;

template<typename T>
auto foo(T f) -> decltype(sin(f)) { return sin(f); }
}

template<typename T>
auto foo(T f) -> decltype(detail::foo(f)) { return detail::foo(f); }

C++ noexcept specification depending on data members

std::declval<T>() simulates an rvalue T instance. std::declval<T&>() simulates an lvalue T instance. Use this in place of T().

ADL in constructor initialization list

You can solve this directly from within the initialiser list, by using a lambda expression: it allows you to write the required helper function inline, and that helper function can contain using std::abs;.

template<typename T>
struct Foo
{
T _data;

Foo(T data):
_data([&](){ using std::abs; return abs(data); }())
{}
};

Why are is_swappable and is_nothrow_swappable not included in C++11?

is_swappable<T> and is_nothrow_swappable<T> were never proposed for C++11. That is the main reason they aren't in C++11. I.e. nothing gets in without being proposed.

So why weren't these proposed?

Speaking from personal experience, I don't propose anything that I haven't implemented and found useful. And though I did implement them for libc++, I did not do so prior to C++11 being published. I simply did not have the time and tools to do so for C++11. My best guess is that this was true of any one else.

Glad you found these useful. You could be the one to propose them for the next C++ standard! Seriously! We need your help!

Update

In response to:

it's a bit of a hack though, because this is only works if swap is
implemented in terms of the Move Constructors and Assignment Operators

Here's test indicating how it behaves on libc++'s implementation:

#include <type_traits>
#include <iostream>

struct A
{
A(const A&);
};

struct B
{
};

void swap(B&, B&);

struct C
{
};

void swap(C&, C&) noexcept;

struct D
{
D(const D&) noexcept;
D& operator=(const D&) noexcept;
};

int main()
{
std::cout << "std::__is_nothrow_swappable<int>::value = "
<< std::__is_nothrow_swappable<int>::value << '\n';
std::cout << "std::__is_nothrow_swappable<A>::value = "
<< std::__is_nothrow_swappable<A>::value << '\n';
std::cout << "std::__is_nothrow_swappable<B>::value = "
<< std::__is_nothrow_swappable<B>::value << '\n';
std::cout << "std::__is_nothrow_swappable<C>::value = "
<< std::__is_nothrow_swappable<C>::value << '\n';
std::cout << "std::__is_nothrow_swappable<D>::value = "
<< std::__is_nothrow_swappable<D>::value << '\n';
}

Which for me outputs:

std::__is_nothrow_swappable<int>::value = 1
std::__is_nothrow_swappable<A>::value = 0
std::__is_nothrow_swappable<B>::value = 0
std::__is_nothrow_swappable<C>::value = 1
std::__is_nothrow_swappable<D>::value = 1


Related Topics



Leave a reply



Submit