2016-02-04 18 views
13

Wiem, że mogę użyć tablicy znaków i listy inicjalizacji, aby wypełnić ciąg znaków.Ciąg C++ - dziwne zachowanie podczas korzystania z konstruktora listy inicjowania

Wygląda na to, że kompilator dokonuje niejawnej promocji z int na initializer_list lub allocator. Ale nie wiem, dlaczego nie daje mi ono żadnego ostrzeżenia i dlaczego to powoduje, że jest ukryty.

Czy możesz mi wyjaśnić, co dzieje się z ciągami s4 i s5?

http://ideone.com/5Agc2T

#include <iostream> 
#include <string> 
using namespace std; 

class A{ 
}; 

int main() { 

    // string::string(charT const* s) 
    string s1("12345"); 
    // 5 - because constructor takes into account null-terminated character 
    cout << s1.size() << endl;  

    // string(std::initializer_list<charT> ilist) 
    string s2({'1','2','3','4','5'}); 
    // 5 - because string is built from the contents of the initializer list init. 
    cout << s2.size()<<endl; 

    // string::string(charT const* s, size_type count) 
    string s3("12345",3); 
    // 3 - Constructs the string with the first count characters of character string pointed to by s 
    cout << s3.size() << endl; 

    // basic_string(std::initializer_list<CharT> init,const Allocator& alloc = Allocator()); - ? 
    string s4({'1','2','3','4','5'},3); 
    // 2 - why this compiles (with no warning) and what this result means? 
    cout << s4.size() << endl; 



    string s5({'1','2','3','4','5'},5); 
    // 0 - why this compiles (with no warning) and what this result means? 
    cout << s5.size() << endl; 

    // basic_string(std::initializer_list<CharT> init,const Allocator& alloc = Allocator()); 
    // doesn't compile, no known conversion for argument 2 from 'A' to 'const std::allocator<char>&' 
    //string s6({'1','2','3','4','5'},A()); 
    //cout << s6.size() << endl; 

    return 0; 
} 
+1

Czy możesz mi wytłumaczyć, czego można się spodziewać zamiast tego, co się dzieje? Nie widzę niczego nie zamierzonego w tym kodzie. – dhein

+0

Tak, oczywiście. Spodziewałem się takiego samego zachowania dla obu konstruktorów, także biorąc pod uwagę tablicę znaków i listy inicjalizatorów. – tomekpe

Odpowiedz

28
string s6({'1','2','3','4','5'},3); 
string s7({'1','2','3','4','5'},5); 

Faktycznie, te pliki uruchamiania nie tylko wywołać konstruktor std::initializer_list. Drugi argument nie może być niejawnie przekonwertowany na std::allocator, więc rozważane są inne konstruktory. Konstruktor nazywany jest jednym z tego podpisu:

basic_string(const basic_string& other, 
       size_type pos, 
       size_type count = std::basic_string::npos, 
       const Allocator& alloc = Allocator()); 

konstruktor std::initializer_list służy do tworzenia tymczasowego std::string z usztywnione-init-listy, aby przekazać jak other argument do powyższego konstruktora. Tymczasowy może się z tym wiązać, ponieważ jest referencją do stałej. Drugi argument to zatem argument pos, który jest używany jako punkt początkowy konstrukcji kopii podłańcuchowej.

Więc s6 to postacie w przedziale [3, 5) (tj "45") i s7 to znaki w przedziale [5,5) (tj "").

+3

Wow. Te pułapki są przykładem tego, co czasami sprawia, że ​​C++ jest trudny do zdobycia. – kebs

+4

Nie rozumiem, czego jeszcze oczekiwał OP! – dhein

+3

Spodziewali się, że kompilator złoży skargę, że nie było żadnej niejawnej konwersji z '5' na' const std :: allocator & 'ponieważ rozważali tylko tego konstruktora jako opcję. –

Powiązane problemy