26 grudnia 2012

C++11/17 - inicjalizacja zmiennych

Nowy standard dostarcza nowy sposób inicjalizacji zmiennych (można nareszcie wygodnie inicjalizować kontenery). Co ciekawe, w przypadku typów prostych i konwersji, która może doprowadzić do utraty danych kompilator wyświetli ostrzeżenie.
#include <iostream>

using namespace std;

int main()
{
    long double ld = 3.1415926536;
    int curly_from_ld_1{ld};    // warning and data lost
    int curly_from_ld_2 = {ld}; // warning and data lost
    cout << ld << " " << curly_from_ld_1 << " " << curly_from_ld_2 << endl;

    int round_from_ld_1(ld);    // no-warning, data lost
    int round_from_ld_2 = ld;   // no-warning, data lost
    cout << ld << " " << round_from_ld_1 << " " << round_from_ld_2 << endl;

    long long ll = 5000000000;
    int curly_from_ll_1{ll};    // warning and data lost
    int curly_from_ll_2 = {ll}; // warning and data lost
    cout << ll << " " << curly_from_ll_1 << " " << curly_from_ll_2 << endl;

    int i = 56;
    long long curly_from_int{i};
    cout << curly_from_int << endl;

    return 0;
}

Testowane z g++ (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008,
$ g++ -std=c++17 main.cpp 

main.cpp: In function ‘int main()’:
main.cpp:8:25: warning: narrowing conversion of ‘ld’ from ‘long double’ to ‘int’ [-Wnarrowing]
    8 |     int curly_from_ld_1{ld};    // warning and data lost
      |                         ^~
main.cpp:9:28: warning: narrowing conversion of ‘ld’ from ‘long double’ to ‘int’ [-Wnarrowing]
    9 |     int curly_from_ld_2 = {ld}; // warning and data lost
      |                            ^~
main.cpp:17:25: warning: narrowing conversion of ‘ll’ from ‘long long int’ to ‘int’ [-Wnarrowing]
   17 |     int curly_from_ll_1{ll};    // warning and data lost
      |                         ^~
main.cpp:18:28: warning: narrowing conversion of ‘ll’ from ‘long long int’ to ‘int’ [-Wnarrowing]
   18 |     int curly_from_ll_2 = {ll}; // warning and data lost
      |                            
Wynik:
3.14159 3 3
3.14159 3 3
5000000000 705032704 705032704
56

Uniform initialization

W C++17 prawie się udało wprowadzić ujednolicony sposób inicjalizacji. Ciągle jeszcze są pewne problemy (linijka 14, a także coś z atomics i agregatami), ale zdaje się że zostaną one naprawione w przyszłych wersjach standardu. W każdym razie programiści są zachęcani, by wszędzie tam gdzie to możliwe stosować klamerki w celu inicjalizacji [1].
#include <iostream>
#include <boost/type_index.hpp>

using namespace std;

int main()
{
    auto var1{17};          // std::initializer_list<int> w C++11, w C++17 int
//  auto var2{1, 3, 6};     // std::initializer_list<int> w C++11, w C++17 ERROR

    cout << boost::typeindex::type_id_with_cvr<decltype(var1)>().pretty_name() << endl;
//  cout << boost::typeindex::type_id_with_cvr<decltype(var2)>().pretty_name();

    auto var3 = {1, 3, 6};  // Ups nieintuicyjne, nadal std::initializer_list<int>

    cout << boost::typeindex::type_id_with_cvr<decltype(var3)>().pretty_name() << endl;
}
Wynik:
int
std::initializer_list<int>
Inne ciekawostki, to inicjalizacja FDT (fundamental data types) domyślną wartością (0, false, nullptr), gdy nawiasy klamerkowe będą puste. Struktury (także dziedziczące), możemy inicjalizować za pomocą zagnieżdżonych nawiasów, ale dodano także wygodne odwoływanie się do nazw pól:
#include <iostream>

using namespace std;

struct Base {
    int age;
    double high;
};

struct Child : public Base {
    string fun() { return name; };
    string name;
};

int main()
{
    int val{};
    cout << "FDT (fundamental data type): " << val << endl;

    Child child1{};     // czyli to samo co child1{0, 0, ""};
    cout << child1.age << " " << child1.high << " " << child1.name << endl;

    Child child2{{.age=1, 2}, .name="Tom"};
    cout << child2.age << " " << child2.high << " " << child2.name << endl;
}
Wynik:
FDT (fundamental data type): 0
0 0 
1 2 Tom

Brak komentarzy:

Prześlij komentarz