cout string without including <string>?

Jan 24, 2018 at 12:53am
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! :)
Jan 24, 2018 at 1:03am
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 Jan 25, 2018 at 1:03am
Jan 24, 2018 at 3:13am
OK, thank you for the explanation!
Jan 24, 2018 at 11:52am
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?
Jan 24, 2018 at 1:01pm
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*
Jan 24, 2018 at 2:02pm
> 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 Jan 24, 2018 at 2:04pm
Jan 25, 2018 at 12:30am
Thank you JLBorges and also thank you Enoizat for mentioning the chapter 6.3.6.2.
Last edited on Jan 25, 2018 at 12:30am
Jan 25, 2018 at 1:05am
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 Jan 25, 2018 at 1:10am
Jan 25, 2018 at 10:24am
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> 
Jan 25, 2018 at 2:33pm
This change (single-element braced-init-lists initialize directly) was retroactively applied to C++14 via a DR.
Topic archived. No new replies allowed.