Fwd: Describing "traits" of a class's members
Hello, A week ago I started a thread here called "Can boost help me organize/parse lots of binary data?" As people started offering help, it because clear I had no idea what I was trying to ask. I come back with a clear question. The attached file defines: 1. TCPosition: an object that describes a position 2. TCDoubleTraits: an object that describes characteristics of a parameter represented as a double 3. TCUnsignedTraits: an object that describes characteristics of a parameter that is represented as an unsigned 4. TCPositionTraits: a collection of TC*Traits plus some boost::function magic to extract parameters from a TCPosition. 5. TCPositionTraits::PrintValues: a function that allows the user to print all values of a TCPosition The motivation for this round-about way of printing the parameters of a "position" is that I have to deal with some objects that have lots of parameters and I would like one central place where I define the characteristics of the values and their order. In this example, that place is TCPositionTraits. In my real life example I will want to store traits such as the way the data is encoded and the way in which the data needs to be transformed into "human readable" format. Question: Can you modify the attached program so that the object TCPositionTraits holds all the traits for the TCPosition object. Not just the traits for the "double" parameters, as is currently the case. Notably missing from TCPositionTraits is a reference to TCPosition::mSteps. Difficulty: This is a difficult question to answer due to the fact that TCPositionTraits has hard-coded in it the keyword "double". I cannot figure out how to remove this. Bonus: Bonus points if your answer looks something like "yes it is possible if you start using a boost concept which you apparently are not aware of". Note: You'll need the C++11 brace-initialization capability to compile this. I used "g++ -std=c++0x test.cpp" with gcc 4.6.3. Thank you, Chris
On Wed, Feb 27, 2013 at 4:08 PM, Chris Stankevitz
Can you modify the attached program so that the object TCPositionTraits holds all the traits for the TCPosition object. Not just the traits for the "double" parameters, as is currently the case. Notably missing from TCPositionTraits is a reference to TCPosition::mSteps.
Attached is an example of how do do this. Drawback: the TCPositionTraits object now has a lot of typing in it. And if/when you create another object (e.g. TCEmployeeTraits) you are going to have to do a lot of typing again. There will be a lot of code duplication. The basic idea is to make TCPositionTraits::TSItem an abstract base class, then create implementations that handle the various types of position parameters. Chris
On Wed, Feb 27, 2013 at 4:49 PM, Chris Stankevitz
Attached is an example of how do do this. Drawback: the TCPositionTraits object now has a lot of typing in it. And if/when you create another object (e.g. TCEmployeeTraits) you are going to have to do a lot of typing again. There will be a lot of code duplication.
Attached is a version that eliminates the code duplication. Drawback: it's now a mess of templates and specializations. Chris
AMDG On 02/27/2013 05:32 PM, Chris Stankevitz wrote:
On Wed, Feb 27, 2013 at 4:49 PM, Chris Stankevitz
wrote: Attached is an example of how do do this. Drawback: the TCPositionTraits object now has a lot of typing in it. And if/when you create another object (e.g. TCEmployeeTraits) you are going to have to do a lot of typing again. There will be a lot of code duplication.
Attached is a version that eliminates the code duplication. Drawback: it's now a mess of templates and specializations.
One more thing that would make this look a bit better: ... mItems = { makeItem(&TCPosition::mLatitude, TCPosition::sLatitudeTraits), ... }; makeItem is a pretty simple function template. In Christ, Steven Watanabe
AMDG On 02/27/2013 04:49 PM, Chris Stankevitz wrote:
On Wed, Feb 27, 2013 at 4:08 PM, Chris Stankevitz
wrote: Can you modify the attached program so that the object TCPositionTraits holds all the traits for the TCPosition object. Not just the traits for the "double" parameters, as is currently the case. Notably missing from TCPositionTraits is a reference to TCPosition::mSteps.
Attached is an example of how do do this. Drawback: the TCPositionTraits object now has a lot of typing in it. And if/when you create another object (e.g. TCEmployeeTraits) you are going to have to do a lot of typing again. There will be a lot of code duplication.
Here's a rough sketch of an interface for a completely different way of going about it. I haven't filled out the implementation of the two macros and for_each_with_traits, but I believe that it is possible using Boost.Fusion. The basic method would be to use BOOST_FUSION_DEFINE_STRUCT_INLINE for TCCLASS, use some kind of template specialization for TCMEMBERTRAITS to associate the trait with the member and implement for_each_with_traits using a combination of fusion zip, for_each, and unfused. template<class T> struct TCTraits; template<> struct TCTraits<double>; // identical to TCDoubleTraits TCCLASS(TCPosition, (double, mLatitude) (double, mAltitude) (unsigned, mSteps) ); TCMEMBERTRAITS(TCPosition::mLatitude) = { "Latitude", "deg", 5, 180/Pi }; TCMEMBERTRAITS(TCPosition::mAltitude) = { "Altitude", "m MSL" }; TCMEMBERTRAITS(TCPosition::mSteps) = { "Steps" }; struct printer { bool WithLabel; bool WithUnits; typedef void result_type; template<class T> void operator()(const T& t, const TCTraits<T>& traits) { std::cout << traits.getString(t, WithLabel, WithUnits) << std::endl; } }; template<class T> void PrintValues(const T& t, bool WithLabel, bool WithUnits) { for_each_with_traits(t, printer{WithLabel, WithUnits}); } In Christ, Steven Watanabe
AMDG On 02/27/2013 04:08 PM, Chris Stankevitz wrote:
Can you modify the attached program so that the object TCPositionTraits holds all the traits for the TCPosition object. Not just the traits for the "double" parameters, as is currently the case. Notably missing from TCPositionTraits is a reference to TCPosition::mSteps.
That's actually pretty easy:
change TCDoubleTraits, TCUnsignedTraits, etc. to
template<class T>
struct TCTraits;
template<>
struct TCTraits<double>;
template<>
struct TCTraits<unsigned>;
change
struct TSItem { ... };
to
template<class T>
struct TSItemImpl
{
const TCTraits<T> *mTraits;
boost::function
Difficulty:
This is a difficult question to answer due to the fact that TCPositionTraits has hard-coded in it the keyword "double". I cannot figure out how to remove this.
Bonus:
Bonus points if your answer looks something like "yes it is possible if you start using a boost concept which you apparently are not aware of".
Note:
You'll need the C++11 brace-initialization capability to compile this. I used "g++ -std=c++0x test.cpp" with gcc 4.6.3.
In Christ, Steven Watanabe
On Wed, Feb 27, 2013 at 5:13 PM, Steven Watanabe
That's actually pretty easy:
typedef boost::variant< TSItemImpl<double>, TSItemImpl<unsigned> > TSItem;
then use boost::apply_visitor for all operations on TSItems.
Steven, Thank you. I will absorb and attempt to incorporate this approach. Or I will fail and let you know know how it fails. Chris
On Wed, Feb 27, 2013 at 5:13 PM, Steven Watanabe
Can you modify the attached program so that the object TCPositionTraits holds all the traits for the TCPosition object. Not just the traits for the "double" parameters, as is currently the case. Notably missing from TCPositionTraits is a reference to TCPosition::mSteps.
That's actually pretty easy:
typedef boost::variant< TSItemImpl<double>, TSItemImpl<unsigned> > TSItem;
then use boost::apply_visitor for all operations on TSItems.
Steven, Thank you for your help with this. I have reworked my code to use boost::variant and am happy with it(*): https://github.com/chrisstankevitz/trait (*) I am working right now to remove the hard-coded references to TCTraitsDouble and TCTraitsUnsigned within Traitses.h and instead make them user-definable via variadic template arguments. I have a question outstanding at comp.lang.c++.moderated which will hopefully give me some direction in that effort. Thank you again for your help and time diving in and understanding what I am attempting to do! Chris
participants (2)
-
Chris Stankevitz
-
Steven Watanabe