What greedy examples of the initializer list are hidden in the standard library?

Since C ++ 11, the standard library containers and std::string have constructors that take a list of initializers. This constructor takes precedence over other constructors (even as @ JohannesSchaub-litb noted in the comments, even ignoring the other “best match” criteria). This leads to several well-known pitfalls when converting all forms in square brackets () constructors to their brackets of version {}

 #include <algorithm> #include <iostream> #include <iterator> #include <vector> #include <string> void print(std::vector<int> const& v) { std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n"; } void print(std::string const& s) { std::cout << s << "\n"; } int main() { // well-known print(std::vector<int>{ 11, 22 }); // 11, 22, not 11 copies of 22 print(std::vector<int>{ 11 }); // 11, not 11 copies of 0 // more surprising print(std::string{ 65, 'C' }); // AC, not 65 copies of 'C' } 

I could not find a third example on this site, and this thing arose in the Lounge chat <C ++> (when discussing with @rightfold, @Abyx and @JerryCoffin). A somewhat surprising thing is that the std::string , using a counter and a character to use {} instead of () , changes its value from n copies of the character to n -th character (usually from the ASCII table), followed by a different character .

This is not caught by the usual prohibition on binding to narrowing conversions, because 65 is a constant expression that can be represented as a char and will retain its original value when converting back to int (§8.5.4 / 7, bullet 4) (thanks @JerryCoffin )

Question : are there any other examples hiding in the standard library where the conversion of the style constructor () to the style {} greedily coincides with the constructor of the list of initializers?

+12
c ++ c ++ 11 initializer-list
Nov 07 '13 at 22:25
source share
2 answers

I assume that with your examples for std::vector<int> and std::string you should also span other containers like std::list<int> , std::deque<int> , etc., which have the same problem, obviously, like std::vector<int> . Similarly, int not the only type, just like for char , short , long and their version unsigned (maybe a few more integral types).

I think there is also std::valarray<T> , but I'm not sure if T allowed to be an integer type. In fact, I think they have different semantics:

 std::valarray<double>(0.0, 3); std::valarray<double>{0.0, 3}; 

There are several other standard C ++ class templates that take the argument std::initializer_list<T> , but I don’t think that any of them have an overloaded constructor that will be used when using brackets instead of brackets.

+4
Nov 07 '13 at
source share

Just looking for the appearance of initializer_list .

  • All sequences, they have constructors similar to constructors:

    • deque
    • dynarray
    • forward_list
    • list
    • vector
  • valarray

  • basic_string

  • Unordered collections, there is a constructor that takes an integer to determine the initial number of bucket.

    • unordered_set
    • unordered_multiset

I think all of this.

 #include <unordered_set> #include <iostream> int main() { std::unordered_set<int> f (3); std::unordered_set<int> g {3}; std::cout << f.size() << "/" << g.size() << std::endl; // prints 0/1. } 
+2
Nov 07 '13 at 22:59
source share



All Articles