patterncppMinor
Should I use an object or type as trait?
Viewed 0 times
objecttypetraitshoulduse
Problem
Edit: Disclaimer: I am new to templates and traits.
I apologize in advance if this is a bad question.
I am refactoring two similar classes with small differences strewn all over them into one template class (or I am trying to anyway).
This is something I just wrote. (I hope I didn't make any mistakes renaming everything.)
So that I can write something like this
But now I am wondering if I shouldn't just have created two different structs and passed those as template parameters instead.
I imagine the calling code would end up looking like this:
So probably somewhat cleaner but I haven't tried it so I don't know if it will actually work.
(I should probably replace the function pointer with a simple one line function that calls the appropriate function for each type in any case.)
Which alternative should I chose? What are the benefits/drawbacks of each?
Does it even make sense to have functions in traits? Should I maybe just use free template functions instead?
I apologize in advance if this is a bad question.
I am refactoring two similar classes with small differences strewn all over them into one template class (or I am trying to anyway).
This is something I just wrote. (I hope I didn't make any mistakes renaming everything.)
// declaration - empty
template
struct SettingsTraits;
// specialization for type CFoo
template <>
struct SettingsTraits
{
typedef CFooRelated RelatedType;
typedef CAttribute & (CDataSource::*AttrGetter)();
static CAttribute & (CDataSource::*GetAttr)();
};
SettingsTraits::AttrGetter SettingsTraits::GetAttr = &CDataSource::GetFooAttr;
// specialization for type CBar
template <>
struct SettingsTraits
{
typedef CBarRelated RelatedType;
typedef CAttribute & (CDataSource::*AttrGetter)();
static CAttribute & (CDataSource::*GetAttr)();
};
SettingsTraits::AttrGetter SettingsTraits::GetAttr = &CDataSource::GetBarAttr;So that I can write something like this
CAttribute::RelatedType> attr = (datasource.*SettingsTraits::GetAttr)();But now I am wondering if I shouldn't just have created two different structs and passed those as template parameters instead.
I imagine the calling code would end up looking like this:
CAttribute attr = FooTraits::GetAttr(datasource);So probably somewhat cleaner but I haven't tried it so I don't know if it will actually work.
(I should probably replace the function pointer with a simple one line function that calls the appropriate function for each type in any case.)
Which alternative should I chose? What are the benefits/drawbacks of each?
Does it even make sense to have functions in traits? Should I maybe just use free template functions instead?
Solution
Yes, the
Notice that this way of doing things doesn't involve global objects or values at all; it's all done entirely within the type system. The compiler can look at the line
Rule of thumb: you should never need to construct a type-traits object at all. If you do, you're probably doing it wrong.
std way of doing things in C++ would be to provide static member functions of your traits type. Consider:// declaration - empty
template
struct SettingsTraits;
// specialization for type CFoo
template <>
struct SettingsTraits
{
typedef CFooRelated RelatedType;
static CAttribute& GetAttrFrom(CDataSource& ds) { return ds.GetFooAttr(); }
};
// specialization for type CBar
template <>
struct SettingsTraits
{
typedef CBarRelated RelatedType;
static CAttribute& GetAttrFrom(CDataSource& ds) { return ds.GetBarAttr(); }
};
typedef SettingsTraits TRAITS;
CAttribute attr = TRAITS::GetAttrFrom(datasource);Notice that this way of doing things doesn't involve global objects or values at all; it's all done entirely within the type system. The compiler can look at the line
TRAITS::GetAttrFrom(datasource) and statically know that it's equivalent to datasource.GetFooAttr(), which means the whole thing compiles down to a single call instruction. Your old code would have required a trip to memory in order to load the value of the pointer SettingsTraits::GetAttr.Rule of thumb: you should never need to construct a type-traits object at all. If you do, you're probably doing it wrong.
Code Snippets
// declaration - empty
template <typename SETTINGS>
struct SettingsTraits;
// specialization for type CFoo
template <>
struct SettingsTraits<CFoo>
{
typedef CFooRelated RelatedType;
static CAttribute<RelatedType>& GetAttrFrom(CDataSource& ds) { return ds.GetFooAttr(); }
};
// specialization for type CBar
template <>
struct SettingsTraits<CBar>
{
typedef CBarRelated RelatedType;
static CAttribute<RelatedType>& GetAttrFrom(CDataSource& ds) { return ds.GetBarAttr(); }
};
typedef SettingsTraits<SETTINGS> TRAITS;
CAttribute<TRAITS::RelatedType> attr = TRAITS::GetAttrFrom(datasource);Context
StackExchange Code Review Q#27361, answer score: 2
Revisions (0)
No revisions yet.