Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fmt::join fails for streamable objects after 6.0.0 #1462

Closed
Quincunx271 opened this issue Dec 6, 2019 · 1 comment
Closed

fmt::join fails for streamable objects after 6.0.0 #1462

Quincunx271 opened this issue Dec 6, 2019 · 1 comment

Comments

@Quincunx271
Copy link

For a type which only has a stream operator, i.e. std::ostream& operator<<(std::ostream&, MyType);, attempting to print it as elements of a range passed to fmt::join fails after 6.0.0:

std::vector<MyType> values = ...;
fmt::print("{}", fmt::join(values, ", "));

In 5.3.0, this compiles and calls the operator<< to print MyType. After 6.0.0, this fails to compile.


MCVE. Works for 5.3.0. Fails for 6.0.0.

#include <ostream>
#include <vector>

#include <fmt/format.h>
#include <fmt/ostream.h>

struct Stream { int p; };

auto operator<<(std::ostream& out, Stream s) -> std::ostream&
{
    return out << "Stream{" << s.p << "}";
}

int main() {
    fmt::print("{}\n", Stream{42});
    auto const values = std::vector{Stream{1}, Stream{2}, Stream{3}};
    fmt::print("[{}]\n", fmt::join(values, ", "));
}

Seemingly relevant parts of the compile error message:

In file included from /opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/format.h:46,
                 from <source>:4:
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h: In substitution of 'template<class T, class Context> using mapped_type_constant = fmt::v6::internal::type_constant<decltype (fmt::v6::internal::arg_mapper<Context>().map(declval<T>())), typename Context::char_type> [with T = fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char>; Context = fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>]':
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:1000:52:   required from 'constexpr long long unsigned int fmt::v6::internal::encode_types() [with Context = fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>; Arg = fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char>; Args = {}]'
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:1101:59:   required from 'constexpr const long long unsigned int fmt::v6::format_arg_store<fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>, fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char> >::types'
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:1180:54:   required from 'fmt::v6::basic_format_args<Context>::basic_format_args(const fmt::v6::format_arg_store<Context, Args ...>&) [with Args = {fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char>}; Context = fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>]'
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:1214:70:   required from 'fmt::v6::format_args::format_args(Args&& ...) [with Args = {fmt::v6::format_arg_store<fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>, fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char> >}]'
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:1409:9:   required from 'void fmt::v6::print(const S&, Args&& ...) [with S = char [6]; Args = {fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char>}; typename std::enable_if<fmt::v6::internal::is_string<S>::value, int>::type <anonymous> = 0]'
<source>:17:49:   required from here
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:843:7: error: no matching function for call to 'fmt::v6::internal::arg_mapper<fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char> >::map(fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char>)'
  843 | using mapped_type_constant =
      |       ^~~~~~~~~~~~~~~~~~~~
...
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:793:46: note: candidate: 'template<class T, typename std::enable_if<(std::is_constructible<fmt::v6::basic_string_view<char>, T>::value && (! fmt::v6::internal::is_string<S>::value)), int>::type <anonymous> > constexpr fmt::v6::basic_string_view<typename S::char_type> fmt::v6::internal::arg_mapper<Context>::map(const T&) [with T = T; typename std::enable_if<(std::is_constructible<fmt::v6::basic_string_view<typename S::char_type>, T>::value && (! fmt::v6::internal::is_string<T>::value)), int>::type <anonymous> = <enumerator>; Context = fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>]'
  793 |   FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
      |                                              ^~~
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:793:46: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:790:13: error: no type named 'type' in 'struct std::enable_if<false, int>'
  790 |             FMT_ENABLE_IF(
      |             ^~~~~~~~~~~~~
...
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:808:43: note: candidate: 'template<class T> constexpr int fmt::v6::internal::arg_mapper<Context>::map(const T*) [with T = T; Context = fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>]'
  808 |   template <typename T> FMT_CONSTEXPR int map(const T*) {
      |                                           ^~~
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:808:43: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:843:7: note:   mismatched types 'const T*' and 'fmt::v6::arg_join<__gnu_cxx::__normal_iterator<const Stream*, std::vector<Stream, std::allocator<Stream> > >, char>'
  843 | using mapped_type_constant =
      |       ^~~~~~~~~~~~~~~~~~~~
...
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:828:26: note: candidate: 'template<class T, typename std::enable_if<(((! fmt::v6::internal::is_string<S>::value) && (! fmt::v6::is_char<T>::value)) && (std::is_constructible<fmt::v6::formatter<T, char, void> >::value || std::is_constructible<fmt::v6::internal::fallback_formatter<T, char, void> >::value)), int>::type <anonymous> > constexpr const T& fmt::v6::internal::arg_mapper<Context>::map(const T&) [with T = T; typename std::enable_if<(((! fmt::v6::internal::is_string<T>::value) && (! fmt::v6::is_char<T>::value)) && (std::is_constructible<typename Context::formatter_type<T> >::value || std::is_constructible<fmt::v6::internal::fallback_formatter<T, typename Context::char_type> >::value)), int>::type <anonymous> = <enumerator>; Context = fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char> >, char>]'
  828 |   FMT_CONSTEXPR const T& map(const T& val) {
      |                          ^~~
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:828:26: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/fmt/6.0.0/include/fmt/core.h:825:13: error: no type named 'type' in 'struct std::enable_if<false, int>'
  825 |             FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
      |             ^~~~~~~~~~~~~
...
@vitaut
Copy link
Contributor

vitaut commented Dec 6, 2019

The old behavior was accidental. To make a type work with join, a formatter specialization should be provided.

@vitaut vitaut closed this as completed Dec 6, 2019
tchaikov added a commit to tchaikov/ceph that referenced this issue Jul 25, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
tchaikov added a commit to tchaikov/ceph that referenced this issue Jul 25, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
tchaikov added a commit to tchaikov/ceph that referenced this issue Jul 25, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
dparmar18 pushed a commit to ceph/ceph-ci that referenced this issue Jul 27, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
dparmar18 pushed a commit to ceph/ceph-ci that referenced this issue Jul 28, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
nizamial09 pushed a commit to ceph/ceph-ci that referenced this issue Aug 1, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
nizamial09 pushed a commit to ceph/ceph-ci that referenced this issue Aug 2, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
bosc0 pushed a commit to bosc0/ceph that referenced this issue Aug 16, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
Pegonzal pushed a commit to ceph/ceph that referenced this issue Oct 13, 2022
* add formatter for classes with stream insertion operator.
  as in fmtlib v6.1.2, which is the one shipped with ubuntu focal,
  fmt::join() requires the printed element to have formatter.
  see fmtlib/fmt#2040 and
  fmtlib/fmt#1462
* use template parameter pack to represent container template argument,
  simpler this way. also, this enables us to print specialized
  classes which uses non-default template parameters.
* use fmt::join() to print container elements. see also
  https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view

Signed-off-by: Kefu Chai <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants