Skip navigation

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
    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:
        return U{std::forward<T>(mX)};

    auto_cast_wrapper(T&& x) :

    auto_cast_wrapper(const auto_cast_wrapper& other) :

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *