0

Recently, I found a bug in my code due to the use of "modern" 'direct list initialization' syntax. The gist of the issue looks like this:

#include <iostream>
#include <string>

int main()
{   
    std::cout << std::string(static_cast<std::size_t>(2), 'y');
    std::cout << std::string{static_cast<std::size_t>(2), 'x'};

    return 0;
}

With the following compilation command:

g++ -std=c++11 main.cpp && ./a.out | xxd

I get the following result:

00000000: 7979 0278                                yy.x

Where we can see that the strings were not initialized in the same way. The first one use the fill string constructor which repeat the char 'y' twice. But for the second one, it seems the braces are interpreted as a std::initializer_list<char>, hence the 0x02 in the binary output.

Both g++ and clang++ produce the same behavior, so I suppose this is to be expected.

The question is then, how do I know if/when my braces are interpreted as an argument list for a constructor or as a single std::initializer_list ?

matovitch
  • 1,264
  • 11
  • 26
  • 2
    My rule of thumb (even though it is 100% accurate), `{}` is always list initialization. If you don't want a list, use `()` instead. – NathanOliver Jun 05 '19 at 13:57
  • 1
    The second initialization is [*list* initialization](https://en.cppreference.com/w/cpp/language/list_initialization), not [direct initialization](https://en.cppreference.com/w/cpp/language/direct_initialization). – Some programmer dude Jun 05 '19 at 13:58
  • @Someprogrammerdude Indeed but in the list-initialization link you provide, they say "both explicit and non-explicit constructors are considered" so why doesn't it default on the same one ? Is there a way to know ? – matovitch Jun 05 '19 at 14:01
  • 1
    @Someprogrammerdude While it is list initialization, it is actually direct list initialization, which is considered direct initialization: https://timsong-cpp.github.io/cppwp/dcl.init#16 – NathanOliver Jun 05 '19 at 14:02
  • Well I think I've found my answer reading a bit: https://stackoverflow.com/a/18224556/2312686 "The `initializer_list<>` constructor is preferred to the other constructors" – matovitch Jun 05 '19 at 14:03
  • 2
    Unfortunately for you `static_cast(2)` is a valid constexpr literal for `char` (and so no narrowing error). – Jarod42 Jun 05 '19 at 14:06
  • Maybe someone could mark it as a duplicate of https://stackoverflow.com/q/27144054/2312686 (I think I cannot). What is strange though here is that the `static_cast` doesn't help. <- Thanks @Jarod42 – matovitch Jun 05 '19 at 14:07
  • 1
    @NathanOliver If I read [this page](https://en.cppreference.com/w/cpp/language/direct_initialization) correctly, case (2) is about "object of **non-class** type" and it adds "(note: for class types and other uses of braced-init-list, see list-initialization)" too. – Bob__ Jun 05 '19 at 14:07
  • 1
    @Jarod42 Is this duplicate really sufficient to answer the question? For me, your comment is as important as the information contains in the duplicate. – Holt Jun 05 '19 at 14:11
  • @Holt I proposed the duplicate but I'm not a SO power user so I will gladly let you debate it. ;) Maybe there is a question somewhere about implicit cast of literals, there is then a combinatorics computation to determine the number of valid questions from the number of "atomic" topics. – matovitch Jun 05 '19 at 14:17

0 Answers0