Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #69986

Re: Initialization of std::vector<std::string> throws

From Bo Persson <bo@bo-persson.se>
Newsgroups comp.lang.c++
Subject Re: Initialization of std::vector<std::string> throws
Date 2019-11-22 16:22 +0100
Message-ID <h3qcpoF446jU1@mid.individual.net> (permalink)
References (1 earlier) <cone.1567599651.572642.18978.1004@monster.email-scan.com> <qkoav3$97d$2@dont-email.me> <qr8frb$47q$1@dont-email.me> <20191122134409.33dffbcff5234841f8ea7411@cvine--nospam--.freeserve.co.uk> <qr8tbg$qem$1@dont-email.me>

Show all headers | View raw


On 2019-11-22 at 16:03, Ralf Goertz wrote:
> Am Fri, 22 Nov 2019 13:44:09 +0000
> schrieb Chris Vine <chris@cvine--nospam--.freeserve.co.uk>:
> 
>> On Fri, 22 Nov 2019 12:12:43 +0100
>> Ralf Goertz <me@myprovider.invalid> wrote:
>>> Since nobody has explained that satisfactorily yet (also see Tim's
>>> answer to Pavel) and I just stumbled over it again, I'd like to
>>> follow up. In the following situation double braces are necessary.
>>> But why? This kind of problem led to my original belief that for
>>> containers they were always needed.
>>>
>>> #include <vector>
>>> #include <iostream>
>>>
>>> struct Foo {
>>>      std::vector<int> v;
>>>      Foo(std::vector<int> v_=std::vector<int>()) : v(v_){}
>>> };
>>>
>>> int main() {
>>>      Foo f{{4,5}};  //double braces needed
>>>      for (auto r:f.v)
>>>          std::cout<<r<<std::endl;
>>>      return 0;
>>> }
>>>
>>>
>>> With single braces I get:
>>> problem.cc: In function ‘int main()’:
>>> problem.cc:10:14: error: no matching function for call to
>>> ‘Foo::Foo(<brace-enclosed initializer list>)’ 10 |     Foo f{4,5};
>>>        |              ^
>>> problem.cc:6:14: note: candidate: ‘Foo::Foo(std::vector<int>)’
>>>      6 |     Foo(std::vector<int> v_=std::vector<int>()) : v(v_){}
>>>        |     ^~~
>>> problem.cc:6:14: note:   candidate expects 1 argument, 2 provided
>>> problem.cc:4:8: note: candidate: ‘Foo::Foo(const Foo&)’
>>>      4 | struct Foo {
>>>        |        ^~~
>>> problem.cc:4:8: note:   candidate expects 1 argument, 2 provided
>>> problem.cc:4:8: note: candidate: ‘Foo::Foo(Foo&&)’
>>> problem.cc:4:8: note:   candidate expects 1 argument, 2 provided
>>
>> I do not have all the previous exchanges available so I may be
>> repeating what others have said, but the reason why single braces fail
>> is because you are passing two arguments to a conversion constructor
>> of Foo taking one (or no) argument.  As to why double braces work, my
>> guess is that (ignoring elision) the inner braces perform an implicit
>> conversion to std::vector<int> via std::vector's constructor taking an
>> initializer_list, constructing a temporary vector with two elements in
>> the vector, and that this then initializes Foo, using std::vector's
>> move constructor.
> 
> Okay I guessed that much, but why can't the compiler do the latter when
> there is only one pair of braces? The error message clearly indicates
> that an initializer list is considered.
> 
> By the way my original question was why a double brace initializer list
> doesn't work for
> 
> std::vector<std::string> pt({{"1","2"}});
> 
> (it compiles but throws a std::length_error because the arguments are
> taken as pointers) but works perfectly for
> 
> std::vector<int> pt({{1,2}});
> 
> On the other hand
> 
> std::vector<std::string> pt({{"1","2","3"}});
> 
> again works as expected (with or without the parenthesis) which I just
> figured out. So the two string element case fails only because the
> compiler picks the wrong constructor. I find that odd because the
> initializer list seems to be the more obvious choice…
> 

It is not *that* obvious to the compiler, as it tries to match an 
initializer_list<char> and you supply two char*. Unfortunately that is a 
better match for std::string(iterator, iterator), but then of course 
fails at runtime as it is not a valid iterator pair.

For *any* number of strings other than 2, the std::string(iterator, 
iterator) will immediately be ruled out, so works much better.


You would have a better chance to match the vector's initializer_list 
constructor if you actually provided som std::string literals:

std::vector<std::string> pt({{"1"s,"2"s}});



     Bo Persson





Back to comp.lang.c++ | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Initialization of std::vector<std::string> throws Ralf Goertz <me@myprovider.invalid> - 2019-09-04 14:09 +0200
  Re: Initialization of std::vector<std::string> throws Sam <sam@email-scan.com> - 2019-09-04 08:20 -0400
    Re: Initialization of std::vector<std::string> throws Ralf Goertz <me@myprovider.invalid> - 2019-09-04 14:33 +0200
      Re: Initialization of std::vector<std::string> throws Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-05 23:26 -0400
        Re: Initialization of std::vector<std::string> throws Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-18 08:37 -0700
      Re: Initialization of std::vector<std::string> throws Ralf Goertz <me@myprovider.invalid> - 2019-11-22 12:12 +0100
        Re: Initialization of std::vector<std::string> throws Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-11-22 13:44 +0000
          Re: Initialization of std::vector<std::string> throws Ralf Goertz <me@myprovider.invalid> - 2019-11-22 16:03 +0100
            Re: Initialization of std::vector<std::string> throws Bo Persson <bo@bo-persson.se> - 2019-11-22 16:22 +0100
            Re: Initialization of std::vector<std::string> throws Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-11-22 16:13 +0000
            Re: Initialization of std::vector<std::string> throws Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-11-28 13:44 -0800
    Re: Initialization of std::vector<std::string> throws "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-11-22 16:30 +0100
  Re: Initialization of std::vector<std::string> throws Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-04 14:43 +0200

csiph-web