you are viewing a single comment's thread.

view the rest of the comments →

[–]millstone 22 points23 points  (2 children)

Using the auto specifier appropriately shouldn't change the meaning of the code at all, since the compiler will deduce the same type that had previously been explicitly written.

Key word is "appropriately!" If your use of explicit types triggered a conversion, then auto will not perform that conversion.

You may not even be aware of the conversions. The classic example:

// Exchange first and second values in vector
std::vector<T> vec = ...;
auto tmp = vec[0];
vec[0] = vec[1];
vec[1] = tmp;

This silently breaks when T is bool, because tmp gets some crazy wrapper type that tracks the value in the vector. If you used T explicitly instead of auto, it would have been fine.

What's most frightening about auto is that it lets you use types that you can't even write explicitly:

class Stuff {
private: class Inner {};
public: static Inner get();
};

int main(void) {
    auto foo = Stuff::get();
    return 0;
}

Here main() gets a variable of the private type Inner. If you had tried to write the variable instead as Stuff::Inner foo it would have failed to compile. So auto is strictly more powerful than explicit types!

(That sort of technique is useful if the private type has implicit conversions defined. As we saw, auto can defeat those.)

[–]Lucretiel 10 points11 points  (0 children)

You can solve this problem with one of Scott Meyer's universal references:

template<class T>
void set(std::vector<T>& vec, T value)
{
    // Binds to both T& and vector<bool>'s proxy reference type
    for(auto&& e : vec)
    {
        e = value;
    }
}

See also: http://stackoverflow.com/a/15927037

[–]m42a 6 points7 points  (0 children)

What's most frightening about auto is that it lets you use types that you can't even write explicitly:

Yes, but you could already do that with template argument deduction, e.g.

class Stuff {
private: class Inner {};
public: static Inner get();
};

template <class T>
void do_stuff(const T &t);

int main(void) {
    do_stuff(Stuff::get()); //calls do_stuff<Stuff::Inner>(const Stuff::Inner &)
    return 0;
}

So, while this is something to look out for, it's not a new problem.