Boost logo

Boost :

Subject: [boost] traits classes vs. metafunctions
From: Stefan Strasser (strasser_at_[hidden])
Date: 2013-03-06 14:36:20


Hi everyone,

are there any guidelines for boost libraries on when to use traits
classes and when to use a metafunction for each member of a would-be
traits class?

I've seen both in boost libraries. c++11 uses traits classes
(iterator_traits, pointer traits, ...), but Abrahams and Gurtovoy [1]
argue that traits classes ("traits blobs") should be avoided "at all
costs" because they are an unnecessary concatenation of multiple
metafunctions into one metafunction with multiple return values.

in practice, this means that if a single 'traits class member' aka
'metafunction result' ought to differ from the defaults, the entire
traits class has to be reimplemented by the user, not only the
metafunction whose result ought to differ from the default.
on the other hand, asking a user to implement 5 or more metafunctions is
much more tedious than implementing a traits class.

possibility 1)

template<...> struct property1 : mpl::bool_<...>{};
template<...> struct property2 : mpl::bool_<...>{};
template<...> struct property3 : mpl::bool_<...>{};

2)

template<...>
struct ..._traits{
    typedef mpl::bool_<...> property1;
    typedef mpl::bool_<...> property2;
    typedef mpl::bool_<...> property3;
};

you could provide both, but in which "direction"?
does a traits class refer to metafunctions, or do metafunctions refer to
a traits class?

a)

template<...>
struct ..._traits{
    typedef typename property1<...>::type property1;
    typedef typename property2<...>::type property2;
    typedef typename property3<...>::type property3;
};

b)

template<...> struct property1 : ..._traits<...>::property1{}
template<...> struct property2 : ..._traits<...>::property2{}
template<...> struct property3 : ..._traits<...>::property3{}

which is accessed when "calling" the metafunction?

it seems to me that metafunctions are better for the "caller" and traits
classes are better for the implementor of the traits/metafunctions.
in my case, the caller is a library and the implementor is the user, so
you might choose a traits class over metafunctions. but what if a new
member is added that wasn't there before (like "property4").
the implementor of an (old) traits class could not have known about the
new member, so accessing the new member (by the library) will result in
an error, while a new metafunction "property4" could simply return a
default.
should new properties of traits classes only be accessed after making
sure they exist, using SFINAE?
there isn't a precedent for this in c++11. only new traits classes were
introduced, but no new members of already existing traits classes.

should metafunctions always be preferred? why did c++11 choose traits
classes over metafunctions, even though the concept of a metafunction
was introduced in c++11 (<type_traits>).

Thanks

[1] Abrahams; Gurtovoy: C++ Template Metaprogramming, 2.2 Metafunctions


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk