Re: Method to get a noexcept-swap check?
Am 30.04.2013 21:48, schrieb Daryle Walker:
I've read about people wondering how to do:
MyClass
{
public:
//...
void swap( MyClass & ) noexcept( /*What goes here?*/ );
//...
};
The answer depends on the noexcept status of the internal component
types' swapping. You could put calls to "swap" in the expression and
hope that ADL is invoked. It would probably be complicated.
The best approach for this is IMO a trait is_nothrow_swappable, where
you implement this once (I have done this for lvalue-swaps and for
heterogeneous any-value-swaps). It is not that hard and can be done
without magic.
Then I
thought about C-level arrays. C++11 adds a version of "std::swap" for
C-level arrays. Since that will have a noexcept setting based on the
extents-stripped type, we could use that to universally check for
swap:
noexcept( std::swap(std::declval<MyType (&)[1]>(),
std::declval<MyType (&)[1]>()) );
This assumes that the built-in array specialization of std::swap
calculates its noexcept status accurately (std::swap for built-ins,
ADL for UDTs, etc.). It can even use compiler magic! Mere users
can't
access any of the magic they use (which may be implementation-
dependent),
but we indirectly access it with this trick.
Is this viable? Is there an easier alternative?
The approach looks basically fine, yes. You may get into trouble, if the
type is one where swap is really defined but is an abstract type (such
as a polymorphic swap), because you cannot form an array type of such
beasts. Here is an example from my compile-time test suite of my own
is_nothrow_swappable trait:
namespace blub {
struct AbstractNoThrow
{
virtual void swap(AbstractNoThrow&) noexcept = 0;
};
void swap(AbstractNoThrow& a, AbstractNoThrow& b) noexcept
{
a.swap(b);
}
struct Abstract
{
virtual void swap(Abstract&) = 0;
};
void swap(Abstract& a, Abstract& b) noexcept(false)
{
a.swap(b);
}
}
static_assert(xstd::is_nothrow_swappable<blub::AbstractNoThrow>::value,
"Error"); // OK
static_assert(noexcept(std::swap(std::declval<blub::AbstractNoThrow
(&)[1]>(),
std::declval<blub::AbstractNoThrow (&)[1]>())), "Error");
// Error: cannot allocate an object of abstract type
static_assert(!xstd::is_nothrow_swappable<blub::Abstract>::value,
"Error"); // OK
static_assert(!noexcept(std::swap(std::declval<blub::Abstract (&)[1]>(),
std::declval<blub::Abstract (&)[1]>())), "Error");
// Error: cannot allocate an object of abstract type
But except from such special cases your approach has been the shortest
version I have seen so far.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]