boost :: lexical_cast с boost :: units :: amount больше не компилируется

У меня проблема с кодом, который анализирует значения, полученные с помощью boost_program_options, для увеличения количества :: единиц. Раньше он работал нормально, а теперь, при новой настройке, больше не работает. Непонятное сообщение об ошибке намекает на проблему с boost :: lexical_cast, которая, похоже, используется программой program_options.

Минимальный пример (в котором я избавился от всех параметров программы):

#include <iostream>
#include <boost/units/io.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/io.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>

using namespace boost::units;

std::istream& operator>>(std::istream& in, quantity<si::current>& c)
{
    c = quantity<si::current>(0.7 * si::ampere);
    return in;
}

int main()
{
    quantity<si::current> c = boost::lexical_cast<quantity<si::current> >("3.0A");
    std::cout << c << std::endl;
}

Это компилируется без ошибок в моей старой настройке (gcc 4.7.2, boost 1.49), но на gcc 4.9.2 с boost 1.55 больше не компилируется (кстати, игнорируйте тот факт, что даже если он компилируется, он выдает исключение в в любом случае, потому что на самом деле из потока ничего не читается; я не хотел запутывать этот пост, включая всю логику синтаксического анализа). Вместо этого я получаю сообщение об ошибке

In file included from /usr/include/boost/serialization/tracking.hpp:20:0,
                 from /usr/include/boost/serialization/nvp.hpp:32,
                 from /usr/include/boost/units/io.hpp:27,
                 from bla3.cpp:2:
/usr/include/boost/lexical_cast.hpp: In instantiation of ‘struct boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::current_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > > > > >’:
/usr/include/boost/lexical_cast.hpp:415:89:   required from ‘struct boost::detail::deduce_target_char<boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::current_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > > > >’
/usr/include/boost/lexical_cast.hpp:674:92:   required from ‘struct boost::detail::lexical_cast_stream_traits<const char*, boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::current_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > > > >’
/usr/include/boost/lexical_cast.hpp:2363:19:   required from ‘static Target boost::detail::lexical_cast_do_cast<Target, Source>::lexical_cast_impl(const Source&) [with Target = boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::current_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > > >; Source = const char*]’
/usr/include/boost/lexical_cast.hpp:2543:50:   required from ‘Target boost::lexical_cast(const Source&) [with Target = boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::current_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > > >; Source = char [5]]’
bla3.cpp:18:81:   required from here
/usr/include/boost/lexical_cast.hpp:388:13: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’
             BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value), 
             ^

Если я использую другой настраиваемый тип (не boost :: units :: amount) в лексическом приведении и перегружаю для него оператор >>, или если я напрямую пытаюсь прочитать количество из строкового потока, все работает нормально.

Может кто-нибудь сказать мне, что я здесь делаю не так?


person fedro    schedule 10.05.2016    source источник
comment
Я даже не могу скомпилировать тривиальный main(), содержащий только это: boost::units::quantity<boost::units::si::current> c;. Не могли бы вы?   -  person John Zwinck    schedule 10.05.2016
comment
@JohnZwinck: Да, без проблем помещаю это в основные компиляции для обеих настроек. Какое сообщение об ошибке вы получаете?   -  person fedro    schedule 10.05.2016
comment
Ах, мне пришлось скомпилировать с -Wno-unused-local-typedef, чтобы избежать спама о неиспользуемых typedef в Boost.   -  person John Zwinck    schedule 10.05.2016


Ответы (1)


Перегруженный оператор, как и бесплатная функция, должен находиться в связанном пространстве имен, чтобы его можно было найти с помощью поиска, зависящего от аргументов.

В этом случае вам нужно будет открыть пространства имен std или boost::units, поскольку аргументы для operator>> находятся в пространствах имен std и boost::units соответственно:

namespace boost { namespace units {

std::istream& operator>>(std::istream& in, quantity<si::current>& c)
{
    c = quantity<si::current>(0.7 * si::ampere);
    return in;
}

}}

Это должно указывать вам, что это не совсем безопасно, поскольку ваш код будет конфликтовать с любым потоком в операторе, предоставленном Boost.Units в будущей версии или другим сторонним пользователем. Вам следует подумать о написании собственной оболочки для quantity<si::current> и предоставлении там оператора stream in.

person ecatmur    schedule 10.05.2016
comment
Большое спасибо, это действительно помогло! Хотя мне интересно, как это работало раньше. Был ли gcc 4.7.2 более снисходительным, чем должен был быть? Кроме того, даже с gcc 4.9.2 поиск перегруженного оператора работает, если я не использую lexical_cast, а просто пытаюсь прочитать quantity<si::current> из _2 _... - person fedro; 10.05.2016
comment
@fedro это сложно; Насколько я могу судить, это разница в версиях boost (gcc 4.7.2 немного устарел, но в этом все сделано правильно). Разница в том, что, начиная с boost 1.53, Boost.LexicalCast учитывает только операторы потока в связанных пространствах имен; это более надежно, поскольку гарантируется, что они будут найдены с помощью поиска, зависящего от аргументов. Поиск без аргументов может привести к нарушению ODR (en.cppreference.com/w / cpp / language / independent_name # Lookup_rules) - person ecatmur; 10.05.2016