cout string without including <string>?

Hello,

I was testing some code and I found out that I didn't need to put "#include <string>" in order to initialize a variable with a string and output it.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <vector>
#include <memory>

int main() {

  auto list = {1,2,3,4,5};
  auto name{"The value is: "};
  auto v = std::make_unique<std::vector<int>>(list);

  for (auto x: *v)
    std::cout << name << x << '\n';
}


The output is:
1
2
3
4
5
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5


How is this possible without having the "#include <string>"?

Is this code ok or we should always use "#include <string>" in our code?

Does the "auto" calls the string library?

Thanks! :)
How is this possible without having the #include <string>?

The implementation is allowed to include the string header, or parts of it, at its whim. This is non-portable -- in other words, it is not required to compile. Best practice is to (directly) include the facilities that you need.

auto has nothing to do with this.

See:
http://www.cplusplus.com/forum/general/221668/#msg1017744

Edit:
std::string is not used in this program.
Last edited on
OK, thank you for the explanation!
Can we be really sure in this example the type of “name” is std::string?

Bjarne Stroustrup, The C++ Programming Language, 4° edition, 6.3.5 Initialization
There is no advantage to using {} initialization, and one trap, when using auto to get the type determined by the initializer. The trap is that if the initializer is a {}-list, we may not want its type deduced (§6.3.6.2). For example:
1
2
auto z1 {99}; // z1 is an initializer_list<int>
auto z2 = 99; // z2 is an int 

So prefer = when using auto.
(The following chapter 6.3.6.2 is entirely about this)

In my opinion, the only thing we can say is “name” is something std::cout has been instructed to manage.
Am I wrong?
Can we be really sure in this example the type of “name” is std::string?

No you can't, in VS 2015 name is actually a const char*
> the only thing we can say is “name” is something std::cout has been instructed to manage.

The language is precise about how the type is deduced (about what that 'something' is).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <type_traits>
#include <cstring>

int main() {

    // alias for 'lvalue reference to array of 15 const char'
    using lvalue_ref_to_array = std::add_lvalue_reference< const char[15] >::type ;

    // type of name is deduced using the rules for template argument deduction for a function call
    // where the parameter is passed by value.
    // the type of the expression "The value is: " is 'array of 15 const char'
    // ergo deduced type is 'pointer to const char'
    auto name = "The value is: ";
    static_assert( std::is_same< decltype(name), const char* >::value,
                   "type of name should be 'pointer to const char'" ) ;
    std::cout << sizeof(name) << '\n' ; // sizeof( const char*)

    // type of name2 is deduced using the deduction rules for decltype
    // the type of the expression "The value is: " is 'array of 15 const char'
    // and its value category is lvalue.
    // ergo, deduced type is 'lvalue reference to array of 15 const char'
    decltype(auto) name2 = "The value is: ";
    static_assert( std::is_same< decltype(name2), lvalue_ref_to_array >::value,
                   "type of name2 should be 'reference to array of 15 const char'" ) ;
    std::cout << sizeof(name2) << '\n' ; // sizeof( const char[15] ) ie. 15

    // type of name3 is deduced using the rules for template argument deduction for a function call
    // where the parameter is passed by lvalue reference.
    // the type of the expression "The value is: " is 'array of 15 const char'
    // ergo, deduced type is 'lvalue reference to array of 15 const char'
    auto& name3 = "The value is: ";
    static_assert( std::is_same< decltype(name3), lvalue_ref_to_array >::value,
                   "type of name3 should be 'reference to array of 15 const char'" ) ;
    std::cout << sizeof(name3) << '\n' ; // sizeof( const char[15] ) ie. 15

    // type of name4 is deduced using the rules for template argument deduction for a function call
    // where the parameter is passed by forwarding reference.
    // the type of the expression "The value is: " is 'array of 15 const char'
    // and its value category is lvalue.
    // ergo, deduced type is 'lvalue reference to array of 15 const char'
    auto&& name4 = "The value is: ";
    static_assert( std::is_same< decltype(name4), lvalue_ref_to_array >::value,
                   "type of name4 should be 'reference to array of 15 const char'" ) ;
    std::cout << sizeof(name4) << '\n' ; // sizeof( const char[15] ) ie. 15
}

http://coliru.stacked-crooked.com/a/82587bf188f8514f
http://rextester.com/TIY54551
Last edited on
Thank you JLBorges and also thank you Enoizat for mentioning the chapter 6.3.6.2.
Last edited on
So in case it's not entirely clear, my response is (partially) wrong, since I missed that that std::string is never used in @Rodev's code. OP's code is portable.
Last edited on
auto z1 {99}; // z1 is an initializer_list<int>

The rules has changed so z1 is now an int in C++17.

Note that the following still gives you an initializer_list.
 
auto z3 = {99}; // z3 is an initializer_list<int> 
This change (single-element braced-init-lists initialize directly) was retroactively applied to C++14 via a DR.
Registered users can post here. Sign in or register to post.