Yes:
auto foo = new Foo(bar);
Maybe: auto foo = FooFactory::newFromBar(bar);
No: auto foo = bar(baz);Yes:
auto foo = new Foo(bar);
Maybe: auto foo = FooFactory::newFromBar(bar);
No: auto foo = bar(baz); auto itemId = item->id(); // Could be an int, could be a string...
processSomeItem(itemId);1. "item->id()" is designed to return a pointer.
2. Consumer of the API writes their code to take a copy of the pointer and passes it along to "processSomeItem". It is cheap to make a copy of a pointer
3. The API is changed and it now returns a reference.
4. The assignment to "itemId" now makes an expensive copy of the object behind the reference causing inefficiency bug.
5. "processSomeItem()" API can handle the copy and the code compiles and runs without the problem being noticed.
std::function<void()> = [] { ... };
Vs: auto = [] { ... }
In the first case you are doing type erasure, which adds quite few penalties. Even in other cases, the type you typed might be convertible from the actual thing that is returned, causing extra conversions. If you always use "auto" the chances you use the right type and do less conversions is way higher.[1] https://github.com/mhogomchungu/tasks
[2] https://github.com/mhogomchungu/tasks/blob/a1512a1b5e0392a06...
template< typename T,typename ... Args >
future<T>& run( std::function< T( Args ... ) > function,Args ... args )
{
return Task::run<T>( std::bind( std::move( function ),std::move( args ) ... ) ) ;
}
It should look like this for that example to work without the type erasure (haven't tried, there might be typos): template< typename Fn,typename ... Args >
future<std::result_of_t(Fn(Args...))>& run( Fn&&, Args&& ... args )
{
return Task::run<std::result_of_t(Fn(Args...))>( std::bind( std::forward<Fn>( function ),std::forward<Args>( args ) ... ) ) ;
}
This version is also more efficient, since otherwise you are type erasing twice.[1] https://github.com/mhogomchungu/tasks/blob/4210a8fad57958fad...
Thank you very much.
Also, passing stuff by reference does not make a copy.
As mentioned in another comment, not being able to name or even easily refer to a type without auto is very common in generic code.
That said, there are awful compiler inferred types that C# doesn't have, so `auto` has a much wider application than `var` does.
std::unordered_map<SomeTemplatedType<A, B>, SomeOtherTemplatedType<C, D>> map = foo();
std::unordered_map<SomeTemplatedType<A, B>, SomeOtherTemplatedType<C, D>>::iterator it = map.begin();
is much less readable than std::unordered_map<SomeTemplatedType<A, B>, SomeOtherTemplatedType<C, D>> map = foo();
auto it = map.begin(); void mutate(Foo &foo);
...
for(auto foo : manyFoos) mutate(foo);
If manyFoos is Foo[], then the auto type is Foo, rather than Foo& and you're mutating a copy. The goal is to not get screwed by the type inference, so unless you can defend why it's obvious that the type is what it is, don't use auto. An auto that you need to ask the IDE for it's concrete type is a strong code smell.(The point about the 'interesting' part is to permit stuff like std::unqiue_ptr<T> F<T>() and the like.)
auto foo = std::make_unique<Foo>(25.3, true);
auto& foo = bar(baz);Duck typing works fine.