jeudi 28 décembre 2017

SFINAE-enabled function template getting instantiated twice and each time differently

I've designed a pretty print/format library using template meta-programming that could print/format objects of any type, as long as they support certain concept(s). For that, I've few overloaded function templates (sfinae-enabled) and I'm using this library in lots of applications. It was working fine using gcc 4.7.3 with -std=c++11.

Now I'm planning to upgrade and use gcc 7.1.0 & -std=c++17. At one place I'm doing equivalent to this:

enum class bad_record;

auto s = pretty::format("%1%, %2%", "hello"s, bad_record{});

It results in lots of compilation errors, with really interesting diagnostic messages; "interesting" because one of the overloaded function template called try_print_nonptr() instantiated twice, each time differently. First it gets instantiated as expected, i.e decltype(out << data, void()) is evaluated to be void, and next time, the same expression is evaluated to be <type-error>, as shown in bold in the error messages below.

I'm unable to reproduce this problem in a small code which I can post here. So I'd really appreciate if anyone could help me understand the scenarios in which such an isssue could come up, so that I can fix my code accordingly.

$gcc/7.1.0R6/include/c++/7.1.0/ostream:656:5: note: candidate: template<class _Ostream, class _Tp> typename std::enable_if<std::__and_<std::__not_<std::is_lvalue_reference<_Tp> >, std::__is_convertible_to_basic_ostream<_Ostream>, std::__is_insertable<_Ostream&, const _Tp&, void> >::value, typename std::__is_convertible_to_basic_ostream<_Tp>::ostream_type>::type std::operator<<(_Ostream&&, const _Tp&) operator<<(_Ostream&& __os, const _Tp& __x) ^~~~~~~~

$gcc/7.1.0R6/include/c++/7.1.0/ostream:656:5: note: template argument deduction/substitution failed: $gcc/7.1.0R6/include/c++/7.1.0/ostream: In substitution of 'template<class _Ostream, class _Tp> typename std::enable_if<std::__and_<std::__not_<std::is_lvalue_reference<_Tp> >, std::__is_convertible_to_basic_ostream<_Ostream>, std::__is_insertable<_Ostream&, const _Tp&, void> >::value, typename std::__is_convertible_to_basic_ostream<_Tp>::ostream_type>::type std::operator<<(_Ostream&&, const _Tp&) [with _Ostream = std::basic_ostream<char>&; _Tp = frap::common::bad_record]':

$/feut/pretty/details/print_impl.hpp:295:8: required from 'decltype (((out << data), void())) feut::pretty::details::try_print_nonptr(std::basic_ostream<_CharT, _Traits>&, const Item&, const feut::meta::preference<1>&) [with CharT = char; Traits = std::char_traits<char>; Item = frap::common::bad_record; decltype (((out << data), void())) = void]'

$/feut/pretty/details/print_impl.hpp:449:20: required from 'void feut::pretty::details::try_print(std::basic_ostream<Char, Traits>&, const Item&, const feut::meta::preference<5>&) [with Item = frap::common::bad_record; CharT = char; Traits = std::char_traits<char>; <template-parameter-1-4> = void]' $/feut/pretty/details/object_proxy.hpp:33:22: required from 'std::basic_ostream<Char, Traits>& feut::pretty::proxy_details::operator<<(std::basic_ostream<Char, Traits>&, const feut::pretty::proxy_details::object_proxy<T>&) [with T = frap::common::bad_record; CharT = char; Traits = std::char_traits<char>]' $/boost/format/feed_args.hpp:99:12:
required from 'void boost::io::detail::put_last(std::basic_ostream<_CharT, _Traits>&, const T&) [with Ch = char; Tr = std::char_traits<char>; T = feut::pretty::proxy_details::object_proxy<frap::common::bad_record>]' $/boost/format/feed_args.hpp:126:17: required from 'void boost::io::detail::call_put_last(std::basic_ostream<_CharT, _Traits>&, const void*) [with Ch = char; Tr = std::char_traits<char>; T = const feut::pretty::proxy_details::object_proxy<frap::common::bad_record>]' $/boost/format/feed_args.hpp:135:47: required from 'boost::io::detail::put_holder<Ch, Tr>::put_holder(T&) [with T = const feut::pretty::proxy_details::object_proxy<frap::common::bad_record>; Ch = char; Tr = std::char_traits<char>]' $/boost/format/feed_args.hpp:307:74: required from 'boost::basic_format<Ch, Tr, Alloc>& boost::io::detail::feed(boost::basic_format<Ch, Tr, Alloc>&, T) [with Ch = char; Tr = std::char_traits<char>; Alloc = std::allocator<char>; T = const feut::pretty::proxy_details::object_proxy<frap::common::bad_record>&]' $/boost/format/format_class.hpp:64:66: required from 'boost::basic_format<Ch, Tr, Alloc>& boost::basic_format<Ch, Tr, Alloc>::operator%(const T&) [with T = feut::pretty::proxy_details::object_proxy<frap::common::bad_record>; Ch = char; Tr = std::char_traits<char>; Alloc = std::allocator<char>]' $/feut/pretty/format.hpp:39:16:
required from 'std::string feut::pretty::format(const char*, const Args& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, frap::common::bad_record}; std::string = std::basic_string<char>]'

$/frap/common/sec_analytics_file_reader.cpp:88:83: required from here

$gcc/7.1.0R6/include/c++/7.1.0/ostream:656:5: error: no type named 'type' in 'struct std::enable_if<false, std::basic_ostream<char>&>'

$/feut/pretty/details/print_impl.hpp: In instantiation of 'decltype (((out << data), void())) feut::pretty::details::try_print_nonptr(std::basic_ostream<_CharT, _Traits>&, const Item&, const feut::meta::preference<1>&) [with CharT = char; Traits = std::char_traits<char>; Item = frap::common::bad_record; decltype (((out << data), void())) = <type error>]':

$/feut/pretty/details/print_impl.hpp:449:20: required from 'void feut::pretty::details::try_print(std::basic_ostream<Char, Traits>&, const Item&, const feut::meta::preference<5>&) [with Item = frap::common::bad_record; CharT = char; Traits = std::char_traits<char>; <template-parameter-1-4> = void]' $/feut/pretty/details/object_proxy.hpp:33:22: required from 'std::basic_ostream<Char, Traits>& feut::pretty::proxy_details::operator<<(std::basic_ostream<Char, Traits>&, const feut::pretty::proxy_details::object_proxy<T>&) [with T = frap::common::bad_record; CharT = char; Traits = std::char_traits<char>]' $/boost/format/feed_args.hpp:99:12:
required from 'void boost::io::detail::put_last(std::basic_ostream<_CharT, _Traits>&, const T&) [with Ch = char; Tr = std::char_traits<char>; T = feut::pretty::proxy_details::object_proxy<frap::common::bad_record>]' $/boost/format/feed_args.hpp:126:17: required from 'void boost::io::detail::call_put_last(std::basic_ostream<_CharT, _Traits>&, const void*) [with Ch = char; Tr = std::char_traits<char>; T = const feut::pretty::proxy_details::object_proxy<frap::common::bad_record>]' $/boost/format/feed_args.hpp:135:47: required from 'boost::io::detail::put_holder<Ch, Tr>::put_holder(T&) [with T = const feut::pretty::proxy_details::object_proxy<frap::common::bad_record>; Ch = char; Tr = std::char_traits<char>]' $/boost/format/feed_args.hpp:307:74: required from 'boost::basic_format<Ch, Tr, Alloc>& boost::io::detail::feed(boost::basic_format<Ch, Tr, Alloc>&, T) [with Ch = char; Tr = std::char_traits<char>; Alloc = std::allocator<char>; T = const feut::pretty::proxy_details::object_proxy<frap::common::bad_record>&]' $/boost/format/format_class.hpp:64:66: required from 'boost::basic_format<Ch, Tr, Alloc>& boost::basic_format<Ch, Tr, Alloc>::operator%(const T&) [with T = feut::pretty::proxy_details::object_proxy<frap::common::bad_record>; Ch = char; Tr = std::char_traits<char>; Alloc = std::allocator<char>]' $/feut/pretty/format.hpp:39:16:
required from 'std::string feut::pretty::format(const char*, const Args& ...) [with Args = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, frap::common::bad_record}; std::string = std::basic_string<char>]'

$/frap/common/sec_analytics_file_reader.cpp:88:83: required from here

Aucun commentaire:

Enregistrer un commentaire