C++

C++ TutorialBasic input/output in c++C++ AlignmentC++ Argument Dependent Name LookupC++ Arithmitic MetaprogrammingC++ ArraysC++ Atomic TypesC++ AttributesC++ autoC++ Basic Type KeywordsC++ Bit fieldsC++ Bit ManipulationC++ Bit OperatorsC++ Build SystemsC++ C incompatibilitiesC++ C++11 Memory ModelC++ Callable ObjectsC++ Classes/StructuresC++ Client server examplesC++ Common compile/linker errors (GCC)C++ Compiling and BuildingC++ Concurrency with OpenMPC++ Const CorrectnessC++ const keywordC++ Constant class member functionsC++ constexprC++ ContainersC++ Copy ElisionC++ Copying vs AssignmentC++ Curiously Recurring Template Pattern (CRTP)C++ Date and time using chrono headerC++ Debugging and Debug-prevention Tools & TechniquesC++ decltypeC++ Digit separatorsC++ EnumerationC++ ExceptionsC++ Explicit type conversionsC++ Expression templatesC++ File I/OC++ Floating Point ArithmeticC++ Flow ControlC++ Fold ExpressionsC++ Friend keywordC++ function call by value vs. call by referenceC++ Function OverloadingC++ Function Template OverloadingC++ Futures and PromisesC++ Header FilesC++ Implementation-defined behaviorC++ Inline functionsC++ Inline variablesC++ IterationC++ IteratorsC++ KeywordsC++ LambdasC++ Layout of object typesC++ Linkage specificationsC++ LiteralsC++ LoopsC++ Memory managementC++ MetaprogrammingC++ Move SemanticsC++ mutable keywordC++ MutexesC++ NamespacesC++ Non-Static Member FunctionsC++ One Definition Rule (ODR)C++ Operator OverloadingC++ operator precedenceC++ OptimizationC++ Overload resolutionC++ Parameter packsC++ Perfect ForwardingC++ Pimpl IdiomC++ PointersC++ Pointers to membersC++ PolymorphismC++ PreprocessorC++ ProfilingC++ RAII: Resource Acquisition Is InitializationC++ Random number generationC++ Recursive MutexC++ Refactoring TechniquesC++ ReferencesC++ Regular expressionsC++ Resource ManagementC++ Return Type CovarianceC++ Returning several values from a functionC++ RTTI: Run-Time Type InformationC++ Scopes



C++ auto

From WikiOD

Remarks[edit | edit source]

The keyword auto is a typename that represents an automatically-deduced type.

It was already a reserved keyword in C++98, inherited from C. In old versions of C++, it could be used to explicitly state that a variable has automatic storage duration:

int main()
{
  auto int i = 5; // removing auto has no effect
}

That old meaning is now removed.

Basic auto sample[edit | edit source]

The keyword auto provides the auto-deduction of type of a variable.

It is especially convenient when dealing with long type names:

std::map< std::string, std::shared_ptr< Widget > > table;
// C++98
std::map< std::string, std::shared_ptr< Widget > >::iterator i = table.find( "42" );
// C++11/14/17
auto j = table.find( "42" );

with range-based for loops:

vector<int> v = {0, 1, 2, 3, 4, 5};
for(auto n: v)
    std::cout << n << ' ';

with lambdas:

auto f = [](){ std::cout << "lambda\n"; };
f();

to avoid the repetition of the type:

auto w = std::make_shared< Widget >();

to avoid surprising and unnecessary copies:

auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);

std::pair<int,float> const& firstPair2 = *myMap.begin();  // copy!
auto const& firstPair = *myMap.begin();  // no copy!

The reason for the copy is that the returned type is actually std::pair<const int,float>!

auto and Expression Templates[edit | edit source]

auto can also cause problems where expression templates come into play:

auto mult(int c) {
    return c * std::valarray<int>{1};
}

auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.

The reason is that operator* on valarray gives you a proxy object that refers to the valarray as a means of lazy evaluation. By using auto, you're creating a dangling reference. Instead of mult had returned a std::valarray<int>, then the code would definitely print 3.

auto, const, and references[edit | edit source]

The auto keyword by itself represents a value type, similar to int or char. It can be modified with the const keyword and the & symbol to represent a const type or a reference type, respectively. These modifiers can be combined.

In this example, s is a value type (its type will be inferred as std::string), so each iteration of the for loop copies a string from the vector into s.

std::vector<std::string> strings = { "stuff", "things", "misc" };
for(auto s : strings) {
    std::cout << s << std::endl;
}

If the body of the loop modifies s (such as by calling s.append(" and stuff")), only this copy will be modified, not the original member of strings.

On the other hand, if s is declared with auto& it will be a reference type (inferred to be std::string&), so on each iteration of the loop it will be assigned a reference to a string in the vector:

for(auto& s : strings) {
    std::cout << s << std::endl;
}

In the body of this loop, modifications to s will directly affect the element of strings that it references.

Finally, if s is declared const auto&, it will be a const reference type, meaning that on each iteration of the loop it will be assigned a const reference to a string in the vector:

for(const auto& s : strings) {
    std::cout << s << std::endl;
}

Within the body of this loop, s cannot be modified (i.e. no non-const methods can be called on it).

When using auto with range-based for loops, it is generally good practice to use const auto& if the loop body will not modify the structure being looped over, since this avoids unnecessary copies.

Trailing return type[edit | edit source]

auto is used in the syntax for trailing return type:

auto main() -> int {}

which is equivalent to

int main() {}

Mostly useful combined with decltype to use parameters instead of std::declval<T>:

template <typename T1, typename T2>
auto Add(const T1& lhs, const T2& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }

Generic lambda (C++14)[edit | edit source]

C++14

C++14 allows to use auto in lambda argument

auto print = [](const auto& arg) { std::cout << arg << std::endl; };

print(42);
print("hello world");

That lambda is mostly equivalent to

struct lambda {
    template <typename T>
    auto operator ()(const T& arg) const {
        std::cout << arg << std::endl;
    }
};

and then

lambda print;

print(42);
print("hello world");

auto and proxy objects[edit | edit source]

Sometimes auto may behave not quite as was expected by a programmer. It type deduces the expression, even when type deduction is not the right thing to do.

As an example, when proxy objects are used in the code:

std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);

Here flag would be not bool, but std::vector<bool>::reference, since for bool specialization of template vector the operator [] returns a proxy object with conversion operator operator bool defined.

When flags.push_back(true) modifies the container, this pseudo-reference could end up dangling, referring to an element that no longer exists.

It also makes the next situation possible:

void foo(bool b);

std::vector<bool> getFlags();

auto flag = getFlags()[5];
foo(flag);

The vector is discarded immediately, so flag is a pseudo-reference to an element that has been discarded. The call to foo invokes undefined behavior.

In cases like this you can declare a variable with auto and initialize it by casting to the type you want to be deduced:

auto flag = static_cast<bool>(getFlags()[5]);

but at that point, simply replacing auto with bool makes more sense.

Another case where proxy objects can cause problems is expression templates. In that case, the templates are sometimes not designed to last beyond the current full-expression for efficiency sake, and using the proxy object on the next causes undefined behavior.

Credit:Stack_Overflow_Documentation