Catch-all traits classes like std::iterator_traits are useful by separating the properties of a type from its definition, so for example the properties may be made available before the definition is complete.
Defining traits in addition to each client class itself is inconvenient, because the traits typically also have a place as members. This is why the generic implementation of std::iterator_traits is defined in terms of its template argument's members.
template< typename it >
struct iterator_traits {
typedef typename it::category category;
typedef typename it::value_type value_type;
// etc
};
Isn't it easier, and less work for the compiler, to use inheritance instead?
template< typename t >
struct t_traits : public t {
t_traits() = delete; // Prevent runtime instances.
};
This fails to document the interface in the primary template, but there are other opportunities for that anyway.
It seems pointless to write lots of repetitive code to define a meta-container class, in an idiom which doesn't even guarantee prevent such abuse as creation at runtime.
Or maybe that's entirely backwards. In addition to std::iterator_traits we also have std::iterator, a pseudo-abstract base class with mostly the same members. Such redundancy is a code smell. Wouldn't it be better if custom iterators looked like this?
template<>
struct iterator_traits< struct my_iterator > {
typedef random_access_iterator_tag category;
typedef foo value_type;
...
};
struct my_iterator : iterator_traits< struct my_iterator > {
...
};
(For the sake of argument, let's ignore the fact that an actual std::iterator_traits specialization must be declared in namespace std. I'm trying to make a familiar illustration of something that might happen in user code.)
This is cleaner in that the idiom need not be violated to handle whatever exceptional case necessitated the fancy footwork in the first place. Instead of the primary traits template producing an internal error that the missing client class is unsuitable for something, there need not be any primary traits template at all.
It's conceptually better to separate qualities of a class from implementation of its services, regardless of whether that separation is necessary. BUT, this style does require breaking every client class into two pieces, including an explicit specialization, which is sort of ugly.
Is anyone familiar with this design space? I'm leaning toward the second idiom, although it looks unusual in practice. But there are probably ins and outs known to those who have trod here before.
The problem with user-defined traits as a specialization of a library type is that a library type belongs to the library. Defining an explicit specialization requires opening the library namespace, which is ugly.
Alternatives 1 and 2 can be combined into a best of both worlds pattern that
always allows optimal separation of concerns (by splitting a class into traits and implementation)
doesn't require splitting a class
never requires opening the library namespace
An extra bit of glue is needed in the form of an ADL based metafunction mapping any class to its traits.
template< typename t >
t traits_type_entry( t const & ); // Declared, never defined.
template< typename t >
using traits_type = decltype( traits_type_entry( std::declval< t >() ) );
By default, T serves as its own traits type as traits_type< T >::type is T. To change this for a given type t to a traits class t_traits, declare (but do not define) a function t_traits traits_type_entry( t const & ). This t_traits class may or may not be a base class of t; the traits_type facility doesn't care. Because the function will be found by argument-depenedent lookup, it may be declared as a friend function with no declaration at namespace scope.
Usage nested inside a class (just to make a difficult test-case) looks like this. For usual usage in a namespace just drop the friend keyword.
class outer_scope {
struct special;
struct special_traits {
typedef int value_type;
constexpr static int limit = 5;
};
friend special_traits traits_type_entry( special const & );
struct unspecial {
typedef double baz_type;
int table[ util::traits_type< special >::limit ];
};
struct special : special_traits {
void f() {
std::pair< typename util::traits_type< unspecial >::baz_type,
value_type >();
}
};
};
http://ideone.com/QztQ6i
Note, the t const & parameter to traits_type_entry can be simply t as long as the class is copyable and destructible.
Also, you could prevent declaring an object of (non-customized) trait type by having the primary template return a type derived from t with its constructor deleted, instead of t itself.
Related
Say I have a template class:
template <typename T> class StringDeque:
public std::deque<T>
{
public:
...
private:
typedef std::deque<T> BaseClass;
};
Say I want to create concrete class ArrayString where T=std::string.
What is the proper way to achieve that:
define
#define ArrayString StringDeque<string>
typedef
typedef StringDeque < string > ArrayString;
inheritance
class ArrayString :
public StringDeque < string > {};
I'm not sure whether all of the suggestions are valid. Anyway I'm trying to figure out which practice most fits.
You want to give a name to a particular type (which happens to be an instantiation of a template). The C++ way to give names (aliases) to types is with a typedef:
typedef StringDeque<string> ArrayString;
Or, since C++11, with an alias declaration:
using ArrayString = StringDeque<string>;
Side note: when thinking about this stuff, it generally helps to think in terms of the correct template terminology. You don't have a "template class" (a class with special properties), you have a "class template" (a template for creating classes). The template is not a type; its instantiations are.
Proper ways:
typedef std::deque<std::string> StringDeque;
using StringDeque = std::deque<string>;
That said, here are some more notes on your question:
You wrote:
template <typename T> class StringDeque: public std::deque<T> // ...
std container classes are not meant as base classes. This means they should not be inherited from (and inheriting from them is UB).
When you want to use std container functionality in another class, the answer should always be encapsulation. That means, the correct way to build on the functionality of std::queue in your classes is:
template<typename T> class StringDequeue {
std::deque<T> storage;
public:
// add interface here that uses storage
};
You also proposed this:
#define ArrayString StringDeque<string>
Please never use define to declare a type. It works, but it has it's own pitfalls and is considered bad practice in C++.
Create type aliases with typedef or (since C++11) using:
typedef StringDeque<std::string> ArrayString;
using ArrayString = StringDeque<std::string>;
The preprocessor is a sledgehammer: occasionally useful but, with no knowledge of language-level constructs, prone to break code in surprising ways. In this case, I think the only problem is that the name won't be constrained to any scope; but that's reason enough to avoid it.
Inheritance creates a new type; while it's usually usable where the base type is, it's not completely interchangable, and doesn't inherit any constructors from the base type. So that's also not what you want for a simple type alias.
I'm exploring template shenanigans in C++ (C++11), and one thing I'd like to have is a pure virtual type in an abstract class. This would be like Scala's abstract types. In C++ I'd want to do something like the following:
struct Base {
// Says any concrete subclass must define Type, but doesn't
// require that it be anything in particular.
virtual typedef MyType;
};
struct Derived : Base {
// Won't compile unless this typedef exists.
typedef int MyType;
};
Any idea how to do this?
I am not sure there is a real need for this in C++.
Trying to put myself in the position of a designer who is looking for such a solution, I would say this kind of constraint would be needed to enforce some types to adhere to some syntactic convention.
Most likely, this is needed because a generic algorithm requires that syntactic convention: it cannot work with types that do not define such a type association.
For instance, the algorithm below requires the type of its argument to have an associated bar_type:
template<typename T>
bool foo(T t)
{
typedef typename T::bar_type FT;
FT ft;
...
}
But if this is the case, there is no need for enforcing a typedef to effectively constraint the input of foo<>(): simply omitting a type definition for bar_type won't make it possible to use that type with foo<>().
Of course, you would discover this only as soon as you actually try to do so, and not before. And being able to define a concept such as HasBarType, and then to enforce some types to realize that concept would be nice; on the other hand, concepts are not yet part of C++ and, as much as they are desirable, it is possible to live without them.
edit
This doesn't work, but I think the curiously recurring template pattern might be the way to go.
/edit
template<typename Dependent>
class Base : public Dependent {
typedef typename Dependent::MyType MyType;
};
Then use the curiously recurring template pattern:
struct Derived : Base<Derived> {
// Won't compile unless this typedef exists.
typedef int MyType;
};
I have a class whose behavior I am trying to configure.
template<int ModeT, bool IsAsync, bool IsReentrant> ServerTraits;
Then later on I have my server object itself:
template<typename TraitsT>
class Server {…};
My question is for my usage above is my naming misnamed? Is my templated parameter actually a policy instead of a trait?
When is a templated argument a trait versus a policy?
Policies
Policies are classes (or class templates) to inject behavior into a parent class, typically through inheritance. Through decomposing a parent interface into orthogonal (independent) dimensions, policy classes form the building blocks of more complex interfaces. An often seen pattern is to supply policies as user-definable template (or template-template) parameters with a library-supplied default. An example from the Standard Library are the Allocators, which are policy template parameters of all STL containers
template<class T, class Allocator = std::allocator<T>> class vector;
Here, the Allocator template parameter (which itself is also a class template!) injects the memory allocation and deallocation policy into the parent class std::vector. If the user does not supply an allocator, the default std::allocator<T> is used.
As is typical in template-based polymporphism, the interface requirements on policy classes are implicit and semantic (based on valid expressions) rather than explicit and syntactic (based on the definition of virtual member functions).
Note that the more recent unordered associative containers, have more than one policy. In addition to the usual Allocator template parameter, they also take a Hash policy that defaults to std::hash<Key> function object. This allows users of unordered containers to configure them along multiple orthogonal dimensions (memory allocation and hashing).
Traits
Traits are class templates to extract properties from a generic type. There are two kind of traits: single-valued traits and multiple-valued traits. Examples of single-valued traits are the ones from the header <type_traits>
template< class T >
struct is_integral
{
static const bool value /* = true if T is integral, false otherwise */;
typedef std::integral_constant<bool, value> type;
};
Single-valued traits are often used in template-metaprogramming and SFINAE tricks to overload a function template based on a type condition.
Examples of multi-valued traits are the iterator_traits and allocator_traits from the headers <iterator> and <memory>, respectively. Since traits are class templates, they can be specialized. Below an example of the specialization of iterator_traits for T*
template<T>
struct iterator_traits<T*>
{
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = std::random_access_iterator_tag;
};
The expression std::iterator_traits<T>::value_type makes it possible to make generic code for full-fledged iterator classes usable even for raw pointers (since raw pointers don't have a member value_type).
Interaction between policies and traits
When writing your own generic libraries, it is important to think about ways users can specialize your own class templates. One has to be careful, however, not to let users fall victim to the One Definition Rule by using specializations of traits to inject rather than to extract behavior. To paraphrase this old post by Andrei Alexandrescu
The fundamental problem is that code that doesn't see the specialized
version of a trait will still compile, is likely to link, and
sometimes might even run. This is because in the absence of the
explicit specialization, the non-specialized template kicks in, likely
implementing a generic behavior that works for your special case as
well. Consequently, if not all the code in an application sees the
same definition of a trait, the ODR is violated.
The C++11 std::allocator_traits avoids these pitfalls by enforcing that all STL containers can only extract properties from their Allocator policies through std::allocator_traits<Allocator>. If users choose not to or forget to supply some of the required policy members, the traits class can step in and supply default values for those missing members. Because allocator_traits itself cannot be specialized, users always have to pass a fully defined allocator policy in order to customize their containers memory allocation, and no silent ODR violations can occur.
Note that as a library-writer, one can still specialize traits class templates (as the STL does in iterator_traits<T*>), but it is good practice to pass all user-defined specializations through policy classes into multi-valued traits that can extract the specialized behavior (as the STL does in allocator_traits<A>).
UPDATE: The ODR problems of user-defined specializations of traits classes happen mainly when traits are used as global class templates and you cannot guarantee that all future users will see all other user-defined specializations. Policies are local template parameters and contain all the relevant definitions, allowing them to be user-defined without interference in other code. Local template parameters that only contain type and constants -but no behaviorally functions- might still be called "traits" but they would not be visible to other code like the std::iterator_traits and std::allocator_traits.
I think you will find the best possible answer to your question in this book by Andrei Alexandrescu. Here, I will try to give just a short overview. Hopefully it will help.
A traits class is class that is usually intended to be a meta-function associating types to other types or to constant values to provide a characterization of those types. In other words, it is a way to model properties of types. The mechanism normally exploits templates and template specialization to define the association:
template<typename T>
struct my_trait
{
typedef T& reference_type;
static const bool isReference = false;
// ... (possibly more properties here)
};
template<>
struct my_trait<T&>
{
typedef T& reference_type;
static const bool isReference = true;
// ... (possibly more properties here)
};
The trait metafunction my_trait<> above associates the reference type T& and the constant Boolean value false to all types T which are not themselves references; on the other hand, it associates the reference type T& and the constant Boolean value true to all types T that are references.
So for instance:
int -> reference_type = int&
isReference = false
int& -> reference_type = int&
isReference = true
In code, we could assert the above as follows (all the four lines below will compile, meaning that the condition expressed in the first argument to static_assert() is satisfied):
static_assert(!(my_trait<int>::isReference), "Error!");
static_assert( my_trait<int&>::isReference, "Error!");
static_assert(
std::is_same<typename my_trait<int>::reference_type, int&>::value,
"Error!"
);
static_assert(
std::is_same<typename my_trait<int&>::reference_type, int&>::value,
"Err!"
);
Here you could see I made use of the standard std::is_same<> template, which is itself a meta-function that accepts two, rather than one, type argument. Things can get arbitrarily complicated here.
Although std::is_same<> is part of the type_traits header, some consider a class template to be a type traits class only if it acts as a meta-predicate (thus, accepting one template parameter). To the best of my knowledge, however, the terminology is not clearly defined.
For an example of usage of a traits class in the C++ Standard Library, have a look at how the Input/Output Library and the String Library are designed.
A policy is something slightly different (actually, pretty different). It is normally meant to be a class that specifies what the behavior of another, generic class should be regarding certain operations that could be potentially realized in several different ways (and whose implementation is, therefore, left up to the policy class).
For instance, a generic smart pointer class could be designed as a template class that accepts a policy as a template parameter for deciding how to handle ref-counting - this is just a hypothetical, overly simplistic, and illustrative example, so please try to abstract from this concrete code and focus on the mechanism.
That would allow the designer of the smart pointer to make no hard-coded commitment as to whether or not modifications of the reference counter shall be done in a thread-safe manner:
template<typename T, typename P>
class smart_ptr : protected P
{
public:
// ...
smart_ptr(smart_ptr const& sp)
:
p(sp.p),
refcount(sp.refcount)
{
P::add_ref(refcount);
}
// ...
private:
T* p;
int* refcount;
};
In a multi-threaded context, a client could use an instantiation of the smart pointer template with a policy that realizes thread-safe increments and decrements of the reference counter (Windows platformed assumed here):
class mt_refcount_policy
{
protected:
add_ref(int* refcount) { ::InterlockedIncrement(refcount); }
release(int* refcount) { ::InterlockedDecrement(refcount); }
};
template<typename T>
using my_smart_ptr = smart_ptr<T, mt_refcount_policy>;
In a single-threaded environment, on the other hand, a client could instantiate the smart pointer template with a policy class that simply increases and decreases the counter's value:
class st_refcount_policy
{
protected:
add_ref(int* refcount) { (*refcount)++; }
release(int* refcount) { (*refcount)--; }
};
template<typename T>
using my_smart_ptr = smart_ptr<T, st_refcount_policy>;
This way, the library designer has provided a flexible solution that is capable of offering the best compromise between performance and safety ("You don't pay for what you don't use").
If you're using ModeT, IsReentrant, and IsAsync to control the behaviour of the Server, then it's a policy.
Alternatively, if you are want a way to describe the characteristics of the server to another object, then you could define a traits class like so:
template <typename ServerType>
class ServerTraits;
template<>
class ServerTraits<Server>
{
enum { ModeT = SomeNamespace::MODE_NORMAL };
static const bool IsReentrant = true;
static const bool IsAsync = true;
}
Here are a couple of examples to clarify Alex Chamberlain's comment:
A common example of a trait class is std::iterator_traits. Let's say we have some template class C with a member function which takes two iterators, iterates over the values, and accumulates the result in some way. We want the accumulation strategy to be defined as part of the template too, but will use a policy rather than a trait to achieve that.
template <typename Iterator, typename AccumulationPolicy>
class C{
void foo(Iterator begin, Iterator end){
AccumulationPolicy::Accumulator accumulator;
for(Iterator i = begin; i != end; ++i){
std::iterator_traits<Iterator>::value_type value = *i;
accumulator.add(value);
}
}
};
The policy is passed in to our template class, while the trait is derived from the template parameter. So what you have is more akin to a policy. There are situations where traits are more appropriate, and where policies are more appropriate, and often the same effect can be achieved with either method leading to some debate about which is most expressive.
Policies are passed through the API by the user to actively choose which code paths should be followed inside a certain interface.
Traits on the other hand are used by the library author to select certain overloads based on what the user passes into the API.
Traits are a way of the library author reacting to the user input, whereas policies are a way for the user to actively influence the library behaviour.
Initially I was trying to typedef a template class and I got to the "gotw 79" article.
And I didn't want to create another class so I ended up doing the following. Basically typedef'ing inside the same class. It works obviously. but is it a good practice?
template <typename T,typename L>
class MyClass{
typedef std::tr1::shared_ptr<MyClass<T,L> > shrdPtr;
}
Thank you.
Well, I'm not a big fan of it unless you are designing MyClass to be specifically used only within shared_ptr objects, at which point I would insist that requirement be enforced.
It's a little ridiculous to put typedefs for every unrelated template instantiation that you might use with a given object. Just because you might put MyClass in a shared_ptr is not a good reason to typedef it there. You going to put typedefs for std::vector, map, list, unordered_map, set, deque,....etc, etc, etc?
But if MyClass extends shared_from_this and has private/protected constructors so that it can ONLY be created and immediately assigned to a shared_ptr then...sure...it's part of the interface.
If you're trying to avoid having to type out long parameter lists to instantiate a shared_ptr for a templated type with lots of parameters then a better bet is an EXTERNAL utility object just like shown in the article you cited:
template < typename T >
struct instantiate_shared_ptr { typedef shared_ptr<T> type; };
template < typename after typename > struct my_complex_template {};
typedef my_complex_template<some parameters> mct_1;
typedef instantiate_shared_ptr<mct_1>::type mct_1_sp;
Yes, especially if the name MyClass_sp is referred to in client code.
This is probably good practice, it makes it simpler if you decide to change the underlying class the typedef refers to at a later date and (arguably) saves typos as well as making code easier to read even if it never changes. The particular choice of name here MyClass_sp leaves a little to be desired in my opinion though.
Also it's worth thinking carefully if making the typedef public or private is most appropriate, i.e. is it part of your public interface?
It's good, IMO.
I used it a lot.
If I want to use a container which element is the type of the my template, I typedef it.
Such as,
template <typename T>
class MyClass {
private:
typedef std::list<T> SomeContainerType;
typedef SomeContainerType::iterator IteratorType;
Then if I find any other structure more suitable, such as a vector, I can change the type without touching too much code.
A better solution for smart pointer typedefs is to do them after the class definition in the header:
namespace N
{
class A
{
};
typedef std::tr1::shared_ptr<A> APtr;
}
This keeps your smart pointer defintion near your class definition while preventing you (and any developers using your code) from having to write code like A::APtr a(new A) (which just looks odd).
EDIT: Since he is concerned with a template class:
namespace N
{
template<class T, class L>
class A
{
};
template<class T, class L>
struct A_Instantiator
{
typedef std::tr1::shared_ptr<A<T, L> > APtr;
};
}
What could be the possible advantages/uses of having an empty class?
P.S:
This question might sound trivial to some of you but it is just for learning purpose and has no practical significance. FYI googling didn't help.
One use would be in template (meta-)programming: for instance, iterator tags are implemented as empty classes. The only purpose here is to pass around information at compilation time so you can check, if an iterator passed to e.g. a template function meets specific requirements.
EXAMPLE:
This is really simplified, just to ge an idea. Here the purpose of the tag class is to decide, which implementation of an algorithm to use:
class forward_iterator_tag {};
class random_access_iterator_tag {};
class MySimpleForwardIterator {
public:
typedef typename forward_iterator_tag tag;
// ...
};
class MySimpleRandomIterator {
public:
typedef typename random_access_iterator_tag tag;
// ...
};
template<class iterator, class tag>
void myfunc_int(iterator it, tag t) {
// general implementation of myfunc
}
template<class iterator>
void myfunc_int<iterator, forward_iterator_tag>(iterator it) {
// Implementation for forward iterators
}
template<class iterator>
void myfunc_int<iterator, random_access_iterator_tag>(iterator it) {
// Implementation for random access iterators
}
template<class iterator>
void myfunc(iterator it) {
myfunc_int<iterator, typename iterator::tag>(it);
}
(I hope I got this right, it's been a while since I used this ...)
With this code, you can call myfunc on an arbitrary iterator, and let the compiler choose the correct implementation depending on the iterator type (i.e. tag).
The following can be used to have a boost::variant which can hold an (SQL) NULL value for example.
class Null { };
typedef boost::variant<Null, std::string, int> Value;
To make it more useful things like operator== and operator<< are handy. For example:
std::ostream& operator<<(std::ostream &lhs, const Null &rhs)
{
lhs << "*NULL*";
return lhs;
}
int main()
{
Variant v("hello");
std::cout << v << std::endl;
v = Null();
std::cout << v << std::endl;
...
}
Will give:
hello
*NULL*
In the STL, Standard Template Library of the C++, for example you have
template<class _Arg,
class _Result>
struct unary_function
{ // base class for unary functions
typedef _Arg argument_type;
typedef _Result result_type;
};
When defining a functor, you can inherit unary_function, and then you have the typedef defined automatically at your disposal.
An empty class could be used as a "token" defining something unique; in certain patterns, you want an implementation-agnostic representation of a unique instance, which has no value to the developer other than its uniqueness. One example is Unit of Work; you may not care one bit about what's going on inside your performer, but you want to tell that performer that the tasks you're telling it to perform are part of an atomic set. An empty class representing the Unit of Work to the outside world may be perfect in this case; almost anything a Unit of Work object could store or do (encapsulating a DB transaction, exposing Commit/Rollback behaviors) would start tying you to a particular implementation, but an object reference is useful to provide a unique but copyable and passable reference to the atomic set of tasks.
You can use it like a placeholder for checking purpose or as enabler to special functionality. For example in Java exist the "empty" interface Serializable used to specify if a class is serializable.
"empty" classes means classes which have no data members?
They typically declare typedefs or member functions, and you can extend them with your own classes.
Here is an interesting link with answers to why its allowed. You might find this helpful to find situations where it might be useful.
As others have said, often an empty class (or struct) is used a placeholder, a differentiator, a token, etc.
For example, a lot of people are unaware that there are "nothrow" versions of operator new. The syntax to invoke nothrow new is:
p = new(std::nothrow) Bar;
and std::nothrow is defined simply as
struct nothrow_t {}; //defined in namespace std
The answer by MartinStettner is fine though just to highlight an important point here: The concept of iterator tags or for that matter any tags in C++, is not strictly dependent on empty classes. The C++ tags, if stl writers would have wanted to, could well have been non-empty classes; that should work but then it won't add any additional value; at least for compile time acrobatics that it is usually reserved for.
For the sake of typeid
Suppose we have comparable interface Id. We need fill some container with unique instances of this interface. How to guarantee the uniqueness of Id instances produced by independent software parts? «Independent parts» means some different dynamic libraries, compiled by different programmers from different locations
One of decisions is to compare typeid of some type first. If typeid matches, convert and compare other implementation specific properties. C++ language guarantees uniqueness of any type within process memory. Which type should be used for this purpose? Any type with minimum resource consumption — empty one