/* * test_signed_integer_output_with_karma_minimal -- Minimal test case * exposing problem in Boost.Spirit.Karma's signed integer output * generators from Boost.Fusion adapted ADTs. * * Copyright (C) 2011 Torsten Maehne * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /*! * \file test_signed_integer_output_with_karma_minimal.cpp * * \brief Minimal test of signed integer output from Boost.Fusion * adapted ADTs and structs with Boost.Spirit.Karma rules. * * Boost.Spirit.Karma output rules should show the same behavior for * Boost.Fusion-adapted structs (direct access of the public member * variables) and ADTs (access to the private member variables via * getters and setters). This has been the case in Boost 1.44 and is * demonstrated in this test case for rational number ADTs and * structs, which use signed integer member variables. * * Compilation of this test case against Boost 1.45.0 and 1.46.1 will * fail. Compilation against Boost 1.47.0 and 1.48.0 will succeed, but * the output of negative values of signed integer members of * Boost.Fusion-adapted ADTs will be wrong. The minus sign is output * correctly, but it is followed by a wrong value, which seems to be * yielded by a cast from a signed to an unsigned integer value * instead of taking the absolute value of the signed integer * value. This has been observed on Mac OS X 10.7.2 (x86_64) with * Xcode 4.2 using Apple's g++ 4.2.1, Apple's clang++ * 3.0. Interestingly, compiling the test case against Boost 1.47.0 or * Boost 1.48.0 using MacPorts g++ 4.5.3, will yield a different wrong * output. * * Compilation against Boost from the Subversion trunk (rev. 76203) * succeeds, but yields the same wrong and compiler-dependent output. * * \author Torsten Maehne * \date 2011-12-28 * \version $Id$ */ #include #include #include #include #if BOOST_VERSION < 104500 // Until Boost 1.44 use BOOST_FUSION_ADAPT_CLASS #include #else // Since Boost 1.45 BOOST_FUSION_ADAPT_CLASS is named BOOST_FUSION_ADAPT_ADT #include #include #endif #include // Include only the strictly necessary parts of Boost.Spirit.Karma to reduce compile time. #include #include #include #include #include namespace { //! Rational number ADT with signed integer members. typedef boost::rational rational_int_adt; //! Rational number struct with signed integer members. struct rational_int_struct { int numerator, denominator; explicit rational_int_struct(int num = 0, int den = 1) : numerator(num), denominator(den) {} }; } // anonymous namespace #if BOOST_VERSION < 104500 // Adapt class boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_CLASS( ::rational_int_adt, (int, int, obj.numerator(), obj.numerator(val)) (int, int, obj.denominator(), obj.denominator(val)) ) #else // Adapt ADT boost::rational to a Fusion sequence. BOOST_FUSION_ADAPT_ADT( ::rational_int_adt, (int, int, obj.numerator(), obj.numerator(val)) (int, int, obj.denominator(), obj.denominator(val)) ) #endif // Adapt struct ::rational_int_struct to a Fusion sequence. BOOST_FUSION_ADAPT_STRUCT( ::rational_int_struct, (int, numerator) (int, denominator) ) int main(int argc, char* argv[]) { // Namespace alias for Boost Spirit Karma. namespace karma = boost::spirit::karma; // Namespace alias for Boost Spirit Phoenix. namespace phx = boost::phoenix; using karma::int_; using boost::spirit::karma::generate; using std::cout; using std::endl; typedef std::ostream_iterator ostr_iter_type; // Output iterator type used as sink for the Boost.Spirit.Karma // generator to the output test stream. ostr_iter_type ostr_iter(cout); //! Check the Karma generator rules for ::rational_int_adt. karma::rule rational_int_adt_; rational_int_adt_.name("rational_int_adt_"); rational_int_adt_ = int_ << '/' << int_; { cout << "rational_int_adt(2, -6) = "; generate(ostr_iter, rational_int_adt_, rational_int_adt(2, -6)); cout << " (expected: -1/3)" << endl; } { cout << "rational_int_adt(-2, 4) = "; // Maybe generate doesn't like temporaries? rational_int_adt rat(-2, 4); generate(ostr_iter, rational_int_adt_, rat); cout << " (expected: -1/2)" << endl; } //! Check the Karma generator rules for ::rational_int_struct. karma::rule rational_int_struct_; rational_int_struct_.name("rational_int_struct_"); rational_int_struct_ = int_ << '/' << int_; { cout << "rational_int_struct(2, -6) = "; generate(ostr_iter, rational_int_struct_, rational_int_struct(2, -6)); cout << " (expected: 2/-6)" << endl; } return 0; }