As a humorous-leaning answer to an unorthodox question, I invented the auto_cast
utility. It looks abusive at first, but is it really so bad? It ended up making a small bit of noise on StackOverflow, so it may not be as bad as it looks.
Here is the final version for C++11:
#include <utility>
template <typename T>
class auto_cast_wrapper
{
public:
template <typename R>
friend auto_cast_wrapper<R> auto_cast(R&& x);
template <typename U>
operator U() const
{
// doesn't allow downcasts, otherwise acts like static_cast
// see: http://stackoverflow.com/questions/5693432/making-auto-cast-safe
return U{std::forward<T>(mX)};
}
private:
auto_cast_wrapper(T&& x) :
mX(std::forward<T>(x))
{}
auto_cast_wrapper(const auto_cast_wrapper& other) :
mX(std::forward<T>(other.mX))
{}
auto_cast_wrapper& operator=(const auto_cast_wrapper&) = delete;
T&& mX;
};
template <typename R>
auto_cast_wrapper<R> auto_cast(R&& x)
{
return auto_cast_wrapper<R>(std::forward<R>(x));
}
And an example:
#include <iostream>
#include <memory>
struct foo
{
typedef std::unique_ptr<int> one_of_those_long_annoying_nested_types;
};
struct bar : foo
{
bar(int&) { std::cout << "lvalue" << std::endl; }
bar(int&&) { std::cout << "rvalue" << std::endl; }
};
foo::one_of_those_long_annoying_nested_types func()
{
// fails, constructor marked explicit
/* return new int; */
// ugly solution, repeats return type
/* return foo::one_of_those_long_annoying_nested_types(new int); */
// nice solution, deduces cast and removes reptition
return auto_cast(new int);
}
int main()
{
// maintains value category
int i = 0;
bar b0 = auto_cast(i);
bar b1 = auto_cast(std::move(i));
// does not allow downcasts (use explicit static_cast for that!)
foo f;
foo& x = f;
foo& y = b0;
bar& z = b1;
/* bar a = auto_cast(x); */
/* bar b = auto_cast(y); */
bar c = auto_cast(z);
}
At first it seemed a bit ugly and something to be avoided, but it does end up looking like a safer way to perform a static_cast
, though one can invert the concept and do this instead:
T x = auto_cast(y); // becomes:
auto x = T{y};
Though you can’t perform that transformation in the context of return values, so auto_cast
retains some usefulness.