#include #include #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) const; private: std::string GetDoubleAsString(double Value) const; }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- std::string TCDoubleTraits::GetString(double Value) const { std::string Return = mLabel; Return.append(" = "); Return.append(GetDoubleAsString(Value)); if (!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) const { std::ostringstream Stream; Stream << mLabel << " = "; Stream << Value; if (!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 all the traits ("traitses") for any object. If you use it // be sure to create a specialization of TCTraitses::mItems for your particular // object, in the order you like. //----------------------------------------------------------------------------- template class TCTraitses { public: static void PrintValues(const TAObject* pObject) { for (const auto& pItem : mItems) { pItem->PrintValue(pObject); } } private: //------------------------------------------------------------------------- //------------------------------------------------------------------------- struct TSItem { virtual ~TSItem() {} virtual void PrintValue(const TAObject* pObject) const = 0; }; //------------------------------------------------------------------------- //------------------------------------------------------------------------- template struct TSItemType : public TSItem { TSItemType( const TATypeTraits* pTypeTraits, boost::function GetType) : mpTypeTraits(pTypeTraits), mGetType(GetType) { } void PrintValue(const TAObject* pObject) const { std::cout << mpTypeTraits->GetString(mGetType(pObject)) << std::endl; } const TATypeTraits* mpTypeTraits; boost::function mGetType; }; static const std::vector> mItems; }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template <> const std::vector::TSItem>> TCTraitses::mItems = { boost::make_shared>( &TCPosition::sLatitudeTraits, boost::bind(&TCPosition::mLatitude, _1)), boost::make_shared>( &TCPosition::sAltitudeTraits, boost::bind(&TCPosition::mAltitude, _1)), boost::make_shared>( &TCPosition::sStepsTraits, boost::bind(&TCPosition::mSteps, _1)) }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int main() { TCPosition Position; Position.mLatitude = 0.2; Position.mAltitude = 321; Position.mSteps = 4; TCTraitses::PrintValues(&Position); return 0; }