#include #include #include #include #include #include #include //----------------------------------------------------------------------------- // This class describes characteristics a double parameter has //----------------------------------------------------------------------------- class TCDoubleTraits { public: TCDoubleTraits( const std::string& Label, const std::string& UiUnits = std::string(), const boost::optional& UiDigitsAfterDecimal = boost::optional(), double InternalToUiScale = 1); std::string mLabel; std::string mUiUnits; boost::optional mUiDigitsAfterDecimal; double mInternalToUiScale; std::string GetString( double Value, bool WithLabel, bool WithUnits) const; private: std::string GetDoubleAsString(double Value) const; }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- std::string TCDoubleTraits::GetString( double Value, bool WithLabel, bool WithUnits) const { std::string Return; if (WithLabel) { Return = mLabel; Return.append(" = "); } Return.append(GetDoubleAsString(Value)); if (WithUnits && !mUiUnits.empty()) { Return.append(" ("); Return.append(mUiUnits); Return.append(")"); } return Return; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- std::string TCDoubleTraits::GetDoubleAsString(double Value) const { if (Value != Value) { return "NaN"; } std::ostringstream Stream; if (mUiDigitsAfterDecimal) { Stream << std::fixed << std::setprecision(*mUiDigitsAfterDecimal); } Stream << Value * mInternalToUiScale; return Stream.str(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- TCDoubleTraits::TCDoubleTraits( const std::string& Label, const std::string& UiUnits, const boost::optional& UiDigitsAfterDecimal, double InternalToUiScale) : mLabel(Label), mUiUnits(UiUnits), mUiDigitsAfterDecimal(UiDigitsAfterDecimal), mInternalToUiScale(InternalToUiScale) { } //----------------------------------------------------------------------------- // This class describes characteristics an unsigned parameter has //----------------------------------------------------------------------------- class TCUnsignedTraits { public: TCUnsignedTraits( const std::string& Label, const std::string& UiUnits = std::string()); std::string mLabel; std::string mUiUnits; std::string GetString( unsigned Value, bool WithLabel, bool WithUnits) const { std::ostringstream Stream; if (WithLabel) { Stream << mLabel << " = "; } Stream << Value; if (WithUnits && !mUiUnits.empty()) { Stream << " (" << mUiUnits << ")"; } return Stream.str(); } }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- TCUnsignedTraits::TCUnsignedTraits( const std::string& Label, const std::string& UiUnits) : mLabel(Label), mUiUnits(UiUnits) { } //----------------------------------------------------------------------------- // This class defines a "position". For each parameter, the "traits" are // provided. //----------------------------------------------------------------------------- class TCPosition { public: double mLatitude; static const TCDoubleTraits sLatitudeTraits; double mAltitude; static const TCDoubleTraits sAltitudeTraits; unsigned mSteps; static const TCUnsignedTraits sStepsTraits; }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- static const double Pi = 3.14159265358979; const TCDoubleTraits TCPosition::sLatitudeTraits( "Latitude", "deg", 5, 180/Pi); const TCDoubleTraits TCPosition::sAltitudeTraits( "Altitude", "m MSL"); const TCUnsignedTraits TCPosition::sStepsTraits("Steps"); //----------------------------------------------------------------------------- // This class holds the traits for a "position" object. It provides a // machanism to write out each of the parameters of a position, provided // you can provide a pointer to a position. The order the values are // printed is defined at compile time in the mItems member. // // Note: This class only supports the "double" members of TCPosition. It // does not allow for different kinds of traits to be stored. //----------------------------------------------------------------------------- class TCPositionTraits { public: static void PrintValues( const TCPosition* pPosition, bool WithLabel, bool WithUnits); private: struct TSItem { TSItem( const TCDoubleTraits* pDoubleTraits, boost::function GetDouble) : mpDoubleTraits(pDoubleTraits), mGetDouble(GetDouble) { } const TCDoubleTraits* mpDoubleTraits; boost::function mGetDouble; }; static const std::vector mItems; }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- const std::vector TCPositionTraits::mItems = { TSItem( &TCPosition::sLatitudeTraits, boost::bind(&TCPosition::mLatitude, _1)), TSItem( &TCPosition::sAltitudeTraits, boost::bind(&TCPosition::mAltitude, _1)) }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void TCPositionTraits::PrintValues( const TCPosition* pPosition, bool WithLabel, bool WithUnits) { for (const auto& Item : mItems) { const double x = Item.mGetDouble(pPosition); std::cout << Item.mpDoubleTraits->GetString( x, WithLabel, WithUnits) << std::endl; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int main() { TCPosition Position; Position.mLatitude = 0.2; Position.mAltitude = 321; Position.mSteps = 4; TCPositionTraits::PrintValues(&Position, true, true); return 0; }