24

A trait in C++ encapsulates a family of operations that allow an Algorithm or Data Structure to operator with that type with which it is instantiated. char_traits are an example for grouping string- and file-required functions.

But not all traits have "trait" in their name, right? numeric_limits comes to mind. Is this a "Trait", too? Even without the name "trait" in it?

So, are there other Templates that could/should be considered a "Trait"? Besides the examples I found:

  • allocator_traits how to get memory
  • pointer_traits how to access an object indirectly
  • type_traits meta programming
  • char_taits for sequence of symbols
  • iterator_traits how to get forward, backward and to the element
  • regex_traits for... regexes.

I guess, what I am asking, too, is there a pure definition for traits?

Some things I am especially unsure about are:

  • numeric_limits mentioned above
  • <chrono>s customization "traits", [20.11.4], i.e. duration_values
  • what about Hashing? Can the functor hash<> be considered to be a trait?
  • If thats the case, are not all requirements "traits", like "CopyAssignable", etc?
  • And then, are the abandoned "Concepts" the ultimate "trait"-Definition?

Update: The question what exactly makes a trait a trait seems a bit controversy in the details. Maybe a another question could be answered: Is there a comprehensive list which of the trait-like classes are new to C++0x, and which ones have already been in C++03? Maybe someone knows of a link to somewhere?

towi
  • 21,587
  • 28
  • 106
  • 187
  • This should be CW, since there are many possible "right" answers. I guess that option no longer exists? Anyway, iostreams facets are a form of trait. – Ben Voigt Jul 16 '11 at 17:58
  • 3
    I do not think `hash<>` is properly considered a trait class, because it does more than just provide compile-time information about the class. How about this definition: "A template class with no non-static members, whose static members depend only on the template argument." – Nemo Jul 16 '11 at 18:40
  • I'd say that `numeric_limits` isn't strictly a trait class, because its values aren't all compile-time static constants or `constexpr` -- you have things like `max()` which is a runtime value. – Kerrek SB Jul 16 '11 at 18:54
  • @Kerrek SB: Nor `char_traits` are strictly compile-time: `length` or `compare` must be evaluated at runtime, too. And as the name suggests, it is considered a trait class. – Vitus Jul 17 '11 at 11:36
  • 1
    I think `numeric_limits` is a perfectly valid traits class. It has no state, and simply supplies information about a type. The fact that some of its information is in the form of static functions doesn't make it less of a traits class, IMO – jalf Jul 31 '11 at 13:03
  • Thank you guys. Especially thanks to Howard and calavek. Alas, I can not split the bounty. But I can *accept* cavaleks answer, because it nicely summarizes my question about traits in general, and I can bounty Howard, because his list is very useful to me, and not many people can produce such a list. Thanks! – towi Aug 06 '11 at 12:38

4 Answers4

10

Here is an attempted list of the traits divided by standard. I could quite easily be overlooking some.

new C++11 traits:

is_error_code_enum
is_error_condition_enum
pointer_traits
allocator_traits
Just about everything in <type_traits>
treat_as_floating_point
duration_values
uses_allocator
regex_traits

C++98/03 traits:

numeric_limits
char_traits
iterator_traits
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • This is most helpful! By your list alone I can probably deduct what (some? all?) of the comittee members considers a trait. I was especially unsure about the `is_error_..._enum`s. And I think I would have missed at least the `treat_as_floating_point` -- I will have to look into that. Thanks a lot. – towi Aug 06 '11 at 12:35
8

  • *numeric_limits* definitely represents a set of traits for the numeric types.
  • all requirements like "CopyAssignable" etc. are indeed traits see this paper on traits

    For the others I cannot comment but when in doubt:

    Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details". - Bjarne Stroustrup

    Update: to just make my small contribution to the extensive list Howard provided:

  • time-related traites
  • regex traits

I was wrongly under the impression that the type traits and regex traits beeing part of the TR1 are technically not part of the new traits bunch in C++0x(even though the type traits have been greatly extended by the new upcoming standard). See Howard's comment and clarification about that.

celavek
  • 5,575
  • 6
  • 41
  • 69
  • Traits are Policies? Hmmm, is this Alexandrescu's opinion as well? – towi Jul 19 '11 at 05:48
  • 1
    I think traits are a particular case of policy classes. Alexandrescu mentions them in his book as a generic programming technique "Traits are a generic programming technique that allows compile-time decisions to be made based on types, much as you would make runtime decisions based on values" but he does not make an explicit mention about traits being policies. – celavek Jul 19 '11 at 08:14
  • 1
    The way I'd separate them is to say that a trait is stateless, and simply gives you information about a type. A policy class may have state, and so you can have different policies for the same type. Also, traits tend to be very small "primitive" types, values and functions ( `value_type`, `max()` for example), where a policy may also define larger compound operations. – jalf Jul 31 '11 at 13:05
  • 1
    TR1 isn't normative. Meaning it isn't a standard. It is just a non-normative document that says "we're interested in this stuff." That being said, it is a common mistake to believe it is normative. Even people on the C++ committee sometimes make that mistake. – Howard Hinnant Aug 01 '11 at 01:37
  • @Howard Hinnant I certainly wasn't aware of that. Thanks for clearing that up. Updated answer. – celavek Aug 01 '11 at 07:57
4

A (type) trait is a simple meta-function in generic programming. It takes one type and returns a set of values, functions and meta-functions describing some aspects of that type.

That means that a trait is a C++ class template. The iterator base classes such as std::forward_iterator_tag aren't traits, for instance.

Notes - Some of the values in a trait may be boolean in nature. Due to C++ template restrictions, trait values cannot be of floating-point type. However, traits can also contain functions, and those functions have no restrictions on return type.

Pure trait classes contain only static members; there's simple no relevant instance data. For that reason, they don't contain constructors either. This "pure" distinction allows us to describe classes like std::vector<T> as non-pure trait classes: they're their own trait classes, in effect.

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

The one that I realy love that goes in hand with the new enum class types is

underlying_type::type which gives you the type of the storage specifier of the enum class

enum class My_Enum : unsigned int { ... }

underlying_type<My_Enum>::type -> unsigned int

Very useful in enum conversions and serialization.

David
  • 3,324
  • 2
  • 27
  • 31
  • If you have a more concrete example, I'd like to see it. – towi Aug 06 '11 at 12:40
  • Code didn't appear properly as I had forgotten the code tag. I'm also not sure what more example you need for this. Any time you use an enum like this you could use this to get the underlying type. This could also be used in an enum_cast<> to cast an enum class from/to an integer. – David Aug 07 '11 at 01:21
  • Ah, I see. I did not know that, Because I did not use the new `enum class`es yet. But that trait example *is* very useful. Thanks. +1. – towi Aug 07 '11 at 10:32