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

Unable to use fmt::join() with user-defined operator<<() #1283

Closed
YukinoHayakawa opened this issue Aug 28, 2019 · 3 comments
Closed

Unable to use fmt::join() with user-defined operator<<() #1283

YukinoHayakawa opened this issue Aug 28, 2019 · 3 comments

Comments

@YukinoHayakawa
Copy link

#include <vector>
#include <string>

#include <fmt/ostream.h>

struct foo
{
    std::string a;
};

std::ostream & operator<<(std::ostream &os, const foo &f)
{
    return os << f.a;
}

int main(int argc, char *argv[])
{
    std::vector<foo> bar;
    fmt::format("{}", fmt::join(bar.begin(), bar.end(), ", "));
}

This used to work.
Now it produces the following errors:

1>------ Build started: Project: ..., Configuration: Debug x64 ------
1>Build started Wed, 8, 28, 2019 5:21:08 PM.
1>Target InitializeBuildStatus:
1>  Touching "x64\Debug\....tlog\unsuccessfulbuild".
1>Target ResolveProjectReferences:
1>Target VcpkgTripletSelection:
1>  Using triplet "x64-windows-static" from "...\vcpkg\installed\x64-windows-static\"
1>Target ClCompile:
1>  Microsoft (R) C/C++ Optimizing Compiler Version 19.22.27905 for x64
1>  Copyright (C) Microsoft Corporation.  All rights reserved.
1>  cl /c /I"...\vcpkg\installed\x64-windows-static\include" /ZI /JMC /W3 /WX /diagnostics:column /sdl /MP /Od /D _UNICODE /D UNICODE /D _SILENCE_CXX17_NEGATORS_DEPRECATION_WARNING /D _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING /D _ENABLE_EXTENDED_ALIGNED_STORAGE /D _CRT_SECURE_NO_WARNINGS /Gm- /EHsc /RTC1 /MTd /GS /fp:precise /permissive- /Zc:wchar_t /Zc:forScope /Zc:inline /Zc:rvalueCast /GR /std:c++17 /Fo"x64\Debug\\" /Fd"x64\Debug\vc142.pdb" /Gd /TP /wd4250 /FC /errorReport:prompt NewFile1.cpp
1>  NewFile1.cpp
1>  ...fmt\core.h(844,1): error C2664:  'const void *fmt::v6::internal::arg_mapper<Context>::map(std::nullptr_t)': cannot convert argument 1 from 'Arg' to 'signed char'
1>  ...fmt\core.h(844,1): error C2664:         with
1>  ...fmt\core.h(844,1): error C2664:         [
1>  ...fmt\core.h(844,1): error C2664:             Context=fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char>>,char>
1>  ...fmt\core.h(844,1): error C2664:         ]
1>  ...fmt\core.h(844,1): error C2664:         and
1>  ...fmt\core.h(844,1): error C2664:         [
1>  ...fmt\core.h(844,1): error C2664:             Arg=fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<foo>>>,char>
1>  ...fmt\core.h(844,1): error C2664:         ]
1>  ...fmt\core.h(844,69): message :  No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>  ...fmt\core.h(1000): message :  see reference to alias template instantiation 'fmt::v6::internal::mapped_type_constant<fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,char>,Context>' being compiled
1>  ...fmt\core.h(1000): message :         with
1>  ...fmt\core.h(1000): message :         [
1>  ...fmt\core.h(1000): message :             _Ty=foo,
1>  ...fmt\core.h(1000): message :             Context=fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char>>,char>
1>  ...fmt\core.h(1000): message :         ]
1>  ...fmt\core.h(1102): message :  see reference to function template instantiation 'unsigned __int64 fmt::v6::internal::encode_types<Context,fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,char>,>(void)' being compiled
1>  ...fmt\core.h(1102): message :         with
1>  ...fmt\core.h(1102): message :         [
1>  ...fmt\core.h(1102): message :             Context=fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char>>,char>,
1>  ...fmt\core.h(1102): message :             _Ty=foo
1>  ...fmt\core.h(1102): message :         ]
1>  ...fmt\core.h(1367): message :  see reference to class template instantiation 'fmt::v6::format_arg_store<fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char>>,char>,fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,char>>' being compiled
1>  ...fmt\core.h(1367): message :         with
1>  ...fmt\core.h(1367): message :         [
1>  ...fmt\core.h(1367): message :             _Ty=foo
1>  ...fmt\core.h(1367): message :         ]
1>  ...\NewFile1.cpp(18): message :  see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> fmt::v6::format<char[3],fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,char>,char>(const S (&),fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,char> &&)' being compiled
1>  ...\NewFile1.cpp(18): message :         with
1>  ...\NewFile1.cpp(18): message :         [
1>  ...\NewFile1.cpp(18): message :             _Ty=foo,
1>  ...\NewFile1.cpp(18): message :             S=char [3]
1>  ...\NewFile1.cpp(18): message :         ]
1>  ...fmt\core.h(999): error C2062:  type 'unknown-type' unexpected
1>  ...fmt\core.h(1000,46): error C2039:  'value': is not a member of '`global namespace''
1>  ...fmt\core.h(1101,7): error C3615:  constexpr function 'fmt::v6::internal::encode_types' cannot result in a constant expression
1>  ...fmt\core.h(1102): message :  failure was caused by control reaching the end of a constexpr function
1>  ...fmt\core.h(1103,62): error C2131:  expression did not evaluate to a constant
1>  ...fmt\core.h(1103,62): message :  failure was caused by a read of an uninitialized symbol
1>  ...fmt\core.h(1103,62): message :  see usage of 'types'
1>Done building target "ClCompile" in project "....vcxproj" -- FAILED.
1>
1>Done building project "....vcxproj" -- FAILED.
1>
1>Build FAILED.
1>
1>...fmt\core.h(844,1): error C2664:  'const void *fmt::v6::internal::arg_mapper<Context>::map(std::nullptr_t)': cannot convert argument 1 from 'Arg' to 'signed char'
1>...fmt\core.h(844,1): error C2664:         with
1>...fmt\core.h(844,1): error C2664:         [
1>...fmt\core.h(844,1): error C2664:             Context=fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char>>,char>
1>...fmt\core.h(844,1): error C2664:         ]
1>...fmt\core.h(844,1): error C2664:         and
1>...fmt\core.h(844,1): error C2664:         [
1>...fmt\core.h(844,1): error C2664:             Arg=fmt::v6::arg_join<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<foo>>>,char>
1>...fmt\core.h(844,1): error C2664:         ]
1>...fmt\core.h(999): error C2062:  type 'unknown-type' unexpected
1>...fmt\core.h(1000,46): error C2039:  'value': is not a member of '`global namespace''
1>...fmt\core.h(1101,7): error C3615:  constexpr function 'fmt::v6::internal::encode_types' cannot result in a constant expression
1>...fmt\core.h(1103,62): error C2131:  expression did not evaluate to a constant
1>    0 Warning(s)
1>    5 Error(s)
1>
1>Time Elapsed 00:00:00.87
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
@vitaut
Copy link
Contributor

vitaut commented Aug 28, 2019

This is a side effect of #952. fmt::join now requires the element type to be formattable (have formatter specialization).

@vitaut vitaut closed this as completed Aug 28, 2019
@YukinoHayakawa
Copy link
Author

It looks like formatter<arg_join<Iter>> derives from formatter<Iter::value_type> which is not defined using operator<< by default anymore (in ostream) due to the changes in #952. So I have to roll my own. The old behavior is moved to internal::fallback_formatter.

My workaround is:

template <typename Char>
struct fmt::formatter<foo, Char> :
    fmt::v6::internal::fallback_formatter<foo, Char> { };

As #952 (comment) suggests, probably it's better to add a trait to enable the old stream formatter by default. It would also make join() more useful as it should be.

@roman-orekhov
Copy link

I wonder why isn't it documented at the API page (together with a workaround).

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

3 participants