<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/61070>61070</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            libc++'s operator<<(ostream, string_view) fails to link without <ostream>
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          davidben
      </td>
    </tr>
</table>

<pre>
    I'm not sure whether this is a bug in libc++, or working as intended, but it's at least a bit strange. So, `operator<<(ostream, string_view)` seems to be specified as defined in `<string_view>`, not `<ostream>`:
https://eel.is/c++draft/string.view.synop
https://eel.is/c++draft/string.view.io
https://en.cppreference.com/w/cpp/string/basic_string_view/operator_ltlt

Does that mean that with just `<string_view>` (and `<iosfwd>` to pick up the types), one should be able to call this function? It seems that way to me.

However, libc++ only declares the function in `<string_view>`:
https://github.com/llvm/llvm-project/blob/1e552d0c5bf1627b92ac205cab07d3e09d911750/libcxx/include/string_view#L959-L962

The actual, inline function definition lives in `<ostream>`:
https://github.com/llvm/llvm-project/blob/1e552d0c5bf1627b92ac205cab07d3e09d911750/libcxx/include/ostream#L1088-L1094

As a result, if you try to call `operator<<(ostream, string_view)` from a TU that only has `<string_view>`, it will compile but fail to link because there is no out-of-line version of the symbol at all. Whereas it works fine in libstdc++.
```
$ cat main.cc
#include <iostream>
#include <string_view>
 
#include "print_string_view.h"
 
int main() {
  PrintStringView(std::cout, "hello world\n");
  return 0;
}
 
$ cat print_string_view.cc
#include "print_string_view.h"
 
#ifdef INCLUDE_OSTREAM
#include <ostream>
#endif
 
void PrintStringView(std::ostream &os, std::string_view s) {
  os << s;
}
 
$ cat print_string_view.h
#include <iosfwd>
#include <string_view>
 
void PrintStringView(std::ostream &os, std::string_view s);
 
$ clang++ -std=c++17 main.cc print_string_view.cc && ./a.out
hello world
$ clang++ -std=c++17 -stdlib=libc++ main.cc print_string_view.cc && ./a.out
/usr/bin/ld: /tmp/print_string_view-20b67d.o: in function `PrintStringView(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string_view<char, std::__1::char_traits<char> >)':
print_string_view.cc:(.text+0x31): undefined reference to `std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<< <char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string_view<char, std::__1::char_traits<char> >)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ clang++ -std=c++17 -stdlib=libc++ -DINCLUDE_OSTREAM main.cc print_string_view.cc && ./a.out
hello world
```

See also this godbolt output:
https://godbolt.org/z/31sWe1faY

I think `operator<<(ostream, string)` is a similar story, which I suspect was the root cause behind this workaround:
https://chromium-review.googlesource.com/c/chromium/src/+/3009579/13/base/check_op.h
(CC @danakj @zmodem)

Is this correct behavior from libc++, or should things be rearranged so that this works without pulling in `<ostream>`?
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUV11v4zoO_TXKC5HAlhs7fshD20ywBbof2Jm7F_tUyBITa6pIhiQnzf31C8pJmrbpoNOdXeACQZtYFC0eHpGHIgS9tohzNr1h08VI9LF1fq7EVqsG7ahxaj-_Y7zagHURQu8Rdi3GFj3EVgfQAQQ0_Rq0BaMbyfhN-tyC87Bz_lHbNYgA2ka0ChWtNH0EHRmvAogIBkWI5ERHCNELu8YJfHVkyMrMdehFdJ4Vt_ThMxeiR7Gh5RC9tuuHrcYd4zUrMwiImwDRQYMQOpR6pVHR6xWutEVFp2Rlxorb873FF3rGb1OIw_LxLcNScc2yBcuu2xi7QL_4kvElopnowPjyELTyYhUZXw6uJ-R6EvbWdZ_drN3FnXYiu87jCj1aiRPpNowvd-Sq604eGF82Imj58AKk5RHOBxNNHLwPfxcOA8RWRNigsMO3nY4tfO9DfA8zYHwmrDosaxdWO3VYiQ46LR-h7yC2CHHfYaAkETEsQmhdbxSlSTQGyVoKYwZKrXoro3aWFUu4i8ecpgOJPZlucHJ-9L-4HW7Rk-tnBoKzZg8KpRE-RYYnvz8iweVMr3Vs--aAtDHb479x5913lJS3xriG8WWO0ylXmZw2q7zkVVNzIXk2laLJKlVgVqs6z6tpRg50I5-eGF9qK02v8JS6Q66K-3paj-_rkp8H-61FEDL2wlC82hptzyJLNNfpq9FbDM-hfoTQ_68wT1e4uM-z2Wx8n2f11XmQ11RUPIbexBTlCvauh-j3J6L8dGVYebcBAd9-G5iU2NGK8KNqoOkGGAPSbTptMJWtldCGDmG0fYQGpegDErk8UiW0Dlwfx241TmnZog-UCrdK_Av7TeMMlTxhzAR-p11UGWOqkwGoQh3KaIjqwOMj08vs8Bl-8iuQdFeFthMpjw-LA8Yw3MZTxi8sv4o4WcBbQ847r208ryKTlnH-YoO2w0kYnzFeA6tuDsvwD9r8Ne39V8rFLERFfCuupetTchnnLRrjCASj2PTWkntes-LkxWPsvYXs9IhVi1cnHuB4e9ZL2HwoJtqwUriCu7_d3v-2-PLw96_f_vnl-q-XsLyANFqlVy8cbp1WP8Lj4AQYL10YOHxYOTsnhFcAuwAD_yF8Ap32HeIcyvjP0ebXBfic-rMAjKCmlkr7OO1cHG5IXh2vwcX80_sYL2HC-FJMiHRD5Tvj3MdeQg-MblixOOsyn3gz48s-eKqldGOWhkAAxpdxQ937jaMxz5qyUhNHZto-13pWZj9A--EhH74MKuBE0VvZCv8C_ZMlrTxEL3QMR7viC1CaKY5LO94qjE_6rxmvTk3p4i2mHjWbRHyKjN9kT0WeeHINvT1Ku5MiovrMyux_BcUF85etCD7r-k-dvZS64QIV14DeExzXqVGipx66IaVI_RPVoCzxSUeQTiHkJCSpk463lLyA1Ae3TookA3n939zQ8eJVBf811eJVP05_vyKCMMENMnbtVONMJEXQ9fE9yTUYTZwnxf4H48siD79jvhL_Pvd8Ry7t48dkz0HxpMks6I02wkOIzu_JZNdq2cIdhJ7mI5LUgzj2zkUY5EyDrbZqCIKUifCut-qdAGTr3Ub3m7HHBOHaubXB4Hp_Gk3kmRmJXC_T1hsKNsvqaVWToiyGiQWTMcrHB9c996fZ7S2wq0wJKx6_07c_Nk7h5pkaA0phOLR03lNsDbZiq50fxN-b6fQwgxCy60CjiEfh0_ypICVRxGcQQuKs6yN0vTE01L4nrZcjNS9UXdRihPO8rKqSl1Oej9p5Pps1V3VT4VTKKa_V9KpCnEksS6nyVYEjPecZLzLOZ7zgPMsnKps1RcHLWkopsa7YVYYboc2EZDmRZqRD6HFe5lmVjYxo0IQ0ynNucQdpkZTNdDHy8yTlm34d2FVmdIjh2UvU0eD8HKEqwMcFdrrW4aSLj0i9wGbUezP_6XkjRUBjcorwPwEAAP__z5otMQ">