Build broken with clang-19: implicit instantiation of undefined template 'std::char_traits<unsigned char>'
In file included from /wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/base64.cc:12:
In file included from /wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/opustags.h:34:
In file included from /usr/include/c++/v1/functional:552:
In file included from /usr/include/c++/v1/__functional/boyer_moore_searcher.h:27:
In file included from /usr/include/c++/v1/vector:325:
In file included from /usr/include/c++/v1/__format/formatter_bool.h:19:
In file included from /usr/include/c++/v1/__format/formatter_integral.h:21:
In file included from /usr/include/c++/v1/__format/formatter_output.h:22:
In file included from /usr/include/c++/v1/__format/parser_std_format_spec.h:39:
/usr/include/c++/v1/string:820:42: error: implicit instantiation of undefined template 'std::char_traits<unsigned char>'
820 | static_assert(is_same<_CharT, typename traits_type::char_type>::value,
| ^
/wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/opustags.h:383:14: note: in instantiation of template class 'std::basic_string<unsigned char>' requested here
383 | byte_string extra_data;
| ^
/usr/include/c++/v1/__fwd/string.h:23:29: note: template is declared here
23 | struct _LIBCPP_TEMPLATE_VIS char_traits;
| ^
In file included from /wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/base64.cc:12:
In file included from /wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/opustags.h:34:
In file included from /usr/include/c++/v1/functional:552:
In file included from /usr/include/c++/v1/__functional/boyer_moore_searcher.h:27:
In file included from /usr/include/c++/v1/vector:325:
In file included from /usr/include/c++/v1/__format/formatter_bool.h:16:
In file included from /usr/include/c++/v1/__format/concepts.h:16:
In file included from /usr/include/c++/v1/__format/format_parse_context.h:16:
/usr/include/c++/v1/string_view:300:42: error: implicit instantiation of undefined template 'std::char_traits<unsigned char>'
300 | static_assert(is_same<_CharT, typename traits_type::char_type>::value,
| ^
/usr/include/c++/v1/__type_traits/is_convertible.h:30:99: note: in instantiation of template class 'std::basic_string_view<unsigned char>' requested here
30 | struct _LIBCPP_TEMPLATE_VIS is_convertible : public integral_constant<bool, __is_convertible(_T1, _T2)> {};
| ^
/usr/include/c++/v1/string:745:29: note: in instantiation of template class 'std::is_convertible<const std::basic_string<unsigned char> &, std::basic_string_view<unsigned char>>' requested here
745 | : public _BoolConstant< is_convertible<const _Tp&, basic_string_view<_CharT, _Traits> >::value &&
| ^
/usr/include/c++/v1/string:1151:27: note: in instantiation of template class 'std::__can_be_converted_to_string_view<unsigned char, std::char_traits<unsigned char>, std::basic_string<unsigned char>>' requested here
1151 | __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
| ^
/usr/include/c++/v1/string:1154:93: note: while substituting prior template arguments into non-type template parameter [with _Tp = std::basic_string<unsigned char>]
1154 | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
1155 | : __r_(__default_init_tag(), __default_init_tag()) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1156 | __self_view __sv = __t;
| ~~~~~~~~~~~~~~~~~~~~~~~
1157 | __init(__sv.data(), __sv.size());
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1158 | }
| ~
/usr/include/c++/v1/string:752:7: note: while substituting deduced template arguments into function template 'basic_string' [with _Tp = std::basic_string<unsigned char>, $1 = (no value)]
752 | class basic_string {
| ^
/wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/opustags.h:357:8: note: while declaring the implicit copy constructor for 'opus_tags'
357 | struct opus_tags {
| ^
/usr/include/c++/v1/__fwd/string.h:23:29: note: template is declared here
23 | struct _LIBCPP_TEMPLATE_VIS char_traits;
| ^
In file included from /wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/base64.cc:12:
In file included from /wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/opustags.h:34:
In file included from /usr/include/c++/v1/functional:552:
In file included from /usr/include/c++/v1/__functional/boyer_moore_searcher.h:27:
In file included from /usr/include/c++/v1/vector:325:
In file included from /usr/include/c++/v1/__format/formatter_bool.h:19:
In file included from /usr/include/c++/v1/__format/formatter_integral.h:21:
In file included from /usr/include/c++/v1/__format/formatter_output.h:22:
In file included from /usr/include/c++/v1/__format/parser_std_format_spec.h:39:
/usr/include/c++/v1/string:2535:5: error: implicit instantiation of undefined template 'std::char_traits<unsigned char>'
2535 | traits_type::copy(std::__to_address(__p), std::__to_address(__old_p), __n_copy);
| ^
/usr/include/c++/v1/string:2556:3: note: in instantiation of member function 'std::basic_string<unsigned char>::__grow_by' requested here
2556 | __grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
| ^
/usr/include/c++/v1/string:2858:7: note: in instantiation of member function 'std::basic_string<unsigned char>::__grow_by_without_replace' requested here
2858 | __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
| ^
/usr/include/c++/v1/string:3302:5: note: in instantiation of member function 'std::basic_string<unsigned char>::append' requested here
3302 | append(__n - __sz, __c);
| ^
/usr/include/c++/v1/string:1303:84: note: in instantiation of member function 'std::basic_string<unsigned char>::resize' requested here
1303 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void resize(size_type __n) { resize(__n, value_type()); }
| ^
/wrkdirs/usr/ports/audio/opustags/work/opustags-1.10.1/src/base64.cc:70:6: note: in instantiation of member function 'std::basic_string<unsigned char>::resize' requested here
70 | out.resize(olen);
| ^
/usr/include/c++/v1/__fwd/string.h:23:29: note: template is declared here
23 | struct _LIBCPP_TEMPLATE_VIS char_traits;
| ^
Version: 1.10.1 FreeBSD 14.1
That’s a tough error. Rewriting the code to use vectors instead of strings would be a work-around but that’s tedious work.
According to https://en.cppreference.com/w/cpp/string/char_traits and https://en.cppreference.com/w/c/string/multibyte/char8_t I expect that changing set(CMAKE_CXX_STANDARD 20) to set(CMAKE_CXX_STANDARD 23) in CMakeLists.txt would eventually work. Could you try that?
there is nothing on those pages indicating that
using basic_string with non-character types is undefined, and the only way to fix it is to actually not do that
std::basic_string can be made to work with other types by supplying a custom char_traits.
The standard library provides std::char_traits<char8_t> and, esoteric platforms aside, char8_t is equivalent to unsigned char which is equivalent to uint8_t. opustags’s using byte_string = std::basic_string<uint8_t> makes sense in that aspect. However, C++ defines char8_t as a distinct type, which explains the types are not interchangeable regarding templates.
That leaves us 3 options:
- Redefining opustags’s byte_string as std::u8string. That’s ugly, but assuming char8_t casts implicitly to unsigned char, it would require few changes, if any. Some casts might be required though, and I’d rather avoid that.
- Defining a custom char_traits for uint8_t so that the current implementation works as-is. Maybe there’s a way to reuse most of char_traits<char8_t>.
- Use a different container type and rewrite the code that uses it.
2 and 3 are both good options in my opinion. We should pick the most convenient one.
Done. std::basic_string<uint8_t> is no more. 82a5124f14142b63b99ba3716d8c677e721bb900
I ended up not overthinking it and using std::string naively. Using char* or equivalent for working with byte strings is not unusual as far as I know.