vendredi 25 mai 2012

C++11 - for_each, auto, constexpr, the begin & the end...

Auto:

It's a new keyword really usefull to code faster but it can be scary to use as it leads to more flexibility and less readability.

srand(1234);

 auto vector_size = 10;

 std::vector<int> a(vector_size);
 auto b = std::vector<int>(vector_size);

 auto lambda = [](int& i){i = abs(i);};

 std::for_each(begin(a), end(a), lambda);

 for each (auto var in a)
 {
  std::cout << var << ",";
 }
 std::cout << std::endl;

and you can also use 'auto' as return type qualifier.

int foo() { return 5; } 
       auto j = foo();

==>  Allows to avoid typos
BUT i recommend an extensive usage of VisualAssistX to change function or variable signature and unit-test improvements.

ConstExpr:

As you may know, C98 doesn't allow to declare an array with an expression.

// Comment
//constexpr int f() //Maybe available in VS'11 Final ...
//{
// return 5;
//}

const int g()
{
 return 5;
}

void ConstExpressionDemo()
{
 const int vector_size = 10;
 int A[vector_size];

 int B[g()];//C++98 cannot compile
 /*int B[f()];*///C++11 should compile if constexpr available.
 
 return;
}

Visual C++ 11: Not available.

But using the compiler static analysis, the following code couldn't compile.

// Comment
constexpr int f() //shouldn't compile ...
{
 return rand();
}


for_each and for-loop improvement:

C# and modern languages provided tools to easily iterate over list, collection or array. Before C++11 programmers who wants to iterate on containers elements wrote loops like:
const auto vector_size = 10;
std::vector<int> a(vector_size);
srand(1234);
  
auto lambda_random_init = [](int& i){i = rand();};

for (std::vector<int>::iterator it = a.begin() ; it != a.end() ;  ++it)
{
  *it = rand();
}

But now we can use auto, lambda, std::for_each and range base for to provide compact, and elegant code.
As example, with the following code we can dump vector, deque or array, in fact any container containing any kind of object supporting "cout".

template<class T> void cout_container(T _Container)
{
    for each (auto var in _Container)
    {
        std::cout << var << ",";
    }
    std::cout << std::endl;
}

cout_container<std::vector<int>>(a);

in the following example i implemented vector initialization using a lambda and several vector accumulation based on different loop-style.

const auto vector_size = 10;
    std::vector<int> a(vector_size);

    srand(1234);

    auto lambda_random_init = [](int& i){i = rand();};

    //init using begin & end 
    std::for_each(begin(a), end(a), lambda_random_init);

    cout_container<std::vector<int>>(a);

    //for_each with lambda capture by ref and return sum
    int sum_of_elems = std::accumulate(begin(a), end(a), 0);
    std::cout << sum_of_elems << std::endl;

    std::for_each(begin(a), end(a), [&sum_of_elems](int& n){ sum_of_elems += n; }); //only 1 elt by ref
    std::cout << sum_of_elems << std::endl;
    std::for_each(begin(a), end(a), [&](int& n){ sum_of_elems += n; });//all elt by ref
    std::cout << sum_of_elems << std::endl;

    int tmp = 0;
    //std::for_each(begin(a), end(a), [&sum_of_elems](int& n){ sum_of_elems += n; tmp = 0; });//cannot compile as tmp is not in the capture list!!!
    std::for_each(begin(a), end(a), [&sum_of_elems, &tmp](int& n){ sum_of_elems += n; tmp += n; });//target several output captured by value !!!
    std::cout << sum_of_elems << " " << tmp << std::endl;

    for each (int& n : A) 
    {
        sum_of_elems += n;
    }
    std::cout << sum_of_elems << std::endl;

    cout_container<std::vector<int>>(a);;

Aucun commentaire :

Enregistrer un commentaire