Traits and passing traits as template parameters - c++

When is it practical to pass traits as template parameters rather than simply using some existing traits struct like
typedef basic_ofstream< char, char_traits<char> >
vs.
typedef basic_ofstream< char >?
I have some tile classes which I would like to have some common ground (traits), so I designed tile_traits to contain all the basic info about a tile, such as int_type and flag_type, like so:
//unspecialized
template<typename T> struct tile_traits;
//... other stuff here, declaration of a tile class
template<>
struct tile_traits<tile_class>
{
typedef tile_class::int_type int_type;
typedef tile_class::flag_type flag_type;
//other possible tile info here.
}
Is designing traits as such considered a traits-blob?

The design of traits is as much art as anything else. There are no hard and
fast answers here. I believe this question has gone unanswered because it is
impossible to give a good answer without knowing a lot more about the problem
you are solving.
In general traits classes are a useful "customization point". That is, if you
are designing a template:
template <class Tile>
class TileContainer
{
...
};
TileContainer might make use of tile_traits<Tile> for some properties of Tile.
And the client of TileContainer can specialize tile_traits<MyTile> in order to
communicate variations of the properties when the default trait (if it exists)
is not correct.
So far I don't think I've said anything you don't already know (judging from
the way your question is worded).
I think your question is:
Should you design:
A)
template <class Tile, class Traits = tile_traits<Tile>>
class TileContainer
{
// uses Traits
};
or:
B)
template <class Tile>
class TileContainer
{
// uses tile_traits<Tile>
};
There are examples of both designs in the C++03 and upcoming C++0x standards.
Example A designs:
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT>>
class basic_string; // both traits and Allocator are traits
template <class Codecvt, class Elem = wchar_t,
class Tr = char_traits<Elem>>
class wbuffer_convert;
template <class T, class Allocator = allocator<T>>
class vector; // Allocator is a A-trait that uses another
// B-trait internally: allocator_traits<Allocator>
template <class charT, class traits = regex_traits<charT>>
class basic_regex;
Example B designs:
template<class Iterator> struct iterator_traits;
template <class Alloc> struct allocator_traits;
template <class Ptr> struct pointer_traits;
template <class Rep> struct treat_as_floating_point;
template <class Rep> struct duration_values;
My only advice is that there is no right or wrong design. Use:
template <class Tile>
class TileContainer
{
// uses tile_traits<Tile>
};
when you are sure that your customer's needs can always be met by specializing
tile_traits<MyTile>.
Use:
template <class Tile, class Traits = tile_traits<Tile>>
class TileContainer
{
// uses Traits
};
when you suspect that your customer may need different traits for the same
Tile, or when you want to force the type of TileContainer to be different when
some trait other than tile_traits is used.

You need to have the traits class as a template parameter if you can see that people would pass different traits for the same data type. If your tiles will always have the same tile_traits for each T, you can use that directly.
If you can see that someone, sometimes, will use a my_special_traits, you need to have that as a separate template parameter.

Seeing you can provide default values for the traits, and having the traits parameter is always more flexible, I would choose this approach unless you have some specific reasons why you cannot do it.
template<class Bar,class Traits=FooTraits<Bar> >
class Foo
{};

Related

Checking for template parent class in C++ using SFINAE

I've been learning the concept of SFINAE in C++ recentlly and I am currentlly trying to use it in a project.
The thing is, what I'm trying to do is different than anything I could find, and I can't figure out how to do it.
Let's say I have a template class called MyParent:
template <typename Elem>
class MyParent;
And a non-template class called MyClass, that inherites it, using char as Elem:
class MyClass : public MyParent<char>;
Now, I want to use SFINAE in order to check if a typename inherites MyParent, regardless of what Elem type is used.
I can't use std::is_base_of, because of the parent's template.
I've tried to do the following:
template <typename T>
struct is_my_parent : std::false_type {};
template <typename Elem>
struct is_my_parent<MyParent<Elem>> : std::true_type {};
Now, if I check for is_my_parent<MyParent<Elem>>::value, it gives me true. Which is good.
However, when I check for is_my_parent<MyClass>::value, I recive false. Which kind of makes sence because MyClass isn't actually MyParent<Elem>, but I didn't manage to get what I wanted.
Is there any convenient way to achive such a thing in C++, other than defining is_my_parent for each and every class that inherites from MyParent?
You might do
template <typename T>
std::true_type is_my_parent_impl(const MyParent<T>*);
std::false_type is_my_parent_impl(const void*);
template <typename T>
using is_my_parent = decltype(is_my_parent_impl(std::declval<T*>()));
Demo
Is there any convenient way to achive such a thing in C++, other than defining is_my_parent for each and every class that inherites from MyParent?
There is, but you'll need to use more elaborate meta-programming techniques. Go entirely back to basics, as it were.
template <class C>
class is_my_parent {
using yes = char;
using no = char[2];
template<typename t>
static yes& check(MyParent<t> const*);
static no& check(...);
public:
enum { value = (1 == sizeof check(static_cast<C*>(0))) };
};
It relies on two basic properties of function overloading and templates:
A derived class can be used to match a function template that takes a base class template as an argument.
Ellipsis offer a conversion sequence that is always considered worse than any other.
Then it's just a matter of inspecting the return type of the chosen overload to determine what we got. Other than the type alias, you can even use this in C++03. Or you can modernize it, so long as overload resolution does the work for you, the check will be performed just the same.
I like Jarod42's answer much better, but an actual SNINAE approach somewhat close to your attempt can work. Here's what I came up with.
To use the type_traits to answer this, we need to know the type of the element. We can make MyParent expose it:
template <typename Elem>
class MyParent {
public:
using ElemType = Elem;
};
Then the default (false) is_my_parent takes an extra arg and the void_t technique* can be used:
template <typename T, typename = void>
struct is_my_parent : std::false_type {};
template <typename T>
struct is_my_parent<T, std::void_t<typename T::ElemType>> :
std::is_base_of<MyParent<typename T::ElemType>, T>::type {};
The specialization is only valid if ElemType is an accessible type in T, and then it results in std::true|false type if the inheritance relationship holds.
live example: https://godbolt.org/z/na5637Knd
But not only is the function overload resolution a better approach for simplicity and size, it will also compile much faster.
(*) void_t was exposed to the world in this fantastic 2-part 2014 talk by Walter Brown. Recommended even if only for review.
https://www.youtube.com/watch?v=Am2is2QCvxY

Why can't you template a template?

In C++ there are 2 template types (to my knowledge): template classes and template functions. Why is it not possible to have a template of template? (be it class, or function, or other template). Has it ever been considered in standards? Does it break C++ syntax/spirit in a way?
I know it may sound crazy, and it's easy to get around.
What is possible with C++:
template<bool b>
class TemplateDependingOnBool
{
public:
template<typename T>
class TheTemplateWeWant{};
}
What would be great:
template<bool b>
template<typename T>
class TheTemplateWeWant{};
and call it in a policy-based style (that's where it's really interesting):
template<typename T, template<typename> class ThePolicy = TheTemplateWeWant<true> >
class Foo {};
The way it's possible to do now is to use:
template<typename T,
template<typename> class ThePolicy = TemplateDependingOnBool<true>::TheTemplateWeWant >
class Foo{};
which is not very elegant.
EDIT:
I know I can template on 2 parameters. The goal is to use the underlying template class (the templated template) as something by itself, be it in a template alias or a template template parameter (as shown in my example).
Policy-based design is a reference to Andrei Alexandrescu's Modern C++ Design, which is the main reason why the feature I'm asking might be useful (because templates are used as template parameters).
With C++11, you're wrong in assuming only two types of templates. There are also type aliases which allow
template <bool b, typename T>
class TheTemplateWeWant { ... };
template<typename T>
using ThePolicy = TheTemplateWeWant<true, T>
If I'm understanding what you're asking correctly (and I'm not entirely clear on your question), then you could write your template taking two parameters:
template <bool b, typename T>
class TheTemplateWeWant { ... };
add a metafunction to partially apply the bool:
template <bool b>
struct PartiallyWant {
template <typename T>
using type = TheTemplateWeWant<b, T>;
};
and then pass that as your policy:
template<typename T,
template<typename> class ThePolicy = PartiallyWant<true>::type >
class Foo { ... };
Foo<char, PartiallyWant<false>::type> foo;
So why not just layer the templates like you propose? The simple answer is that there's no reason to. If TheTemplateWeWant has two template parameters (bool b and typename T, regardless of whether it's an "inner" class or not), then we should express it as such. And if we want to only apply one type or the other, that's something that has fewer use-cases than a general template while also being solvable with just a few lines of boilerplate. Additionally, what if we had such a feature, and now I want to partially apply the T instead of the b? With a few lines of boilerplate I can again accomplish the same thing, but with the layering this would be impossible.
As far as i know you cand you simply that, and it works just as you want - class templated with 2 parameters.
template<bool b, typename T>
class TheTemplateWeWant{}; //valid in C++
What you're describing is partial binding of template parameters, just like std::bind can turn a binary function into a unary function.
For metaprogramming madness, there's Boost.MPL. They do have a template boost::mpl::bind.

Clarification in template declaration, alias and specialization in regards to custom allocators and stl

Sorry for the vague title, but I don't know exactly which is the correct term (and even if it's possible to do the following).
Let's say I have somewhere a template class (an allocator):
template<class Arena, typename T> Allocator
{
public:
Allocator(Arena a);
...
};
Then I have another class, which is in some kind of relation with Allocator, but can't specialize T param in instantiation.
The idea is declare a "not specialized alias" for it, and let the specialization be somewhere else.
Something like:
class MemoryArena
{
using Allocator<T> = AnAllocatorStrategy<T>; //not legal, but just to give the idea
void* Allocate(size_t);
};
The usage should be something like:
Arena anArena(...);
Arena::Allocator<int> allocInt; // some way declare a specialization of the alias
std::vector<int, Arena::Allocator<int>> myVec(allocInt);
The main idea behind that, is that because of stl container need a specialized allocator on the contained element's type, I can still use the same memory arena and let the specialized instances to forward the allocate call to it.
But I still would like that is the Arena itself controlling the base allocation strategy (eventually also parametrazing the not completely specialized AllocatorStrategy ).
Any hint on this? Is this possible?
EDIT
Thanks to the comment I fixed the declaration using alias templates this way:
class MemoryArena
{
template<typename T> using MyAllocatorTemplate = Allocator<MemoryArena, T>;;
void* Allocate(size_t);
};
I still need to figure out if it's possible make Allocator be part of MemoryArena definition, without fully specify T parameter. Something like:
template<class AllocatorType<MemoryArena,?> = DefaultAllocType<MemoryArena,?>> //is possible not to specify T on MemoryArena definition?
class MemoryArena<AllocatorType>
{
template<typename T> using MyAllocatorTemplate = AllocatorType<MemoryArena,T>;
Alternatively, any other suggestion is appreciated. The main goal is to let the user specify the Arena's allocator type except for the T parameter (useful only for using the allocator inside containers).
template<template<class...>class Z, class...T0s>
struct partial_apply {
template<class...T1s>
using result = Z<T0s...,T1s...>;
};
template<template<class...>class A, template<class...>class B>
struct same_template : std::false_type {};
template<template<class...>class A>
struct same_template<A,A> : std::true_type {};
template<class...>class Default {};
template<
template<class...>class AllocatorType=Default
>
class MemoryArena {
template<class T>
using MyAllocatorTemplate = std::conditional_t<
same_template<AllocatorType, Default>{},
DefaultAllocType<MemoryArena, T>,
AllocatorType<T>
>;
};
suppose there is some other alloc type besides DefaultAllocType, OtherAllocType<Chicken, T>. Then:
template<class...Ts>
using OtherAllocChicken = partial_apply<OtherAllocType, Chicken>::template result<Ts...>;
using ChickenArena = MemoryArena< OtherAllocChicken >;
on the other hand, if you require that the argument passed to the incoming template be MemoryArena itself sometimes, things get more complex.
Before MemoryArena is parameterized, the type doesn't exist. So you have to have some kind of placeholder that can tell you where you should inject it.
If you want it to always be MemoryArena, then things are easier: you already have that solution:
template<template<class...>class AllocatorType = DefaultAllocType>
class MemoryArena {
template<typename T>
using MyAllocatorTemplate = AllocatorType<MemoryArena,T>;
};

Why is allocator::rebind necessary when we have template template parameters?

Every allocator class must have an interface similar to the following:
template<class T>
class allocator
{
...
template<class Other>
struct rebind { typedef allocator<Other> other; };
};
And classes that use allocators do something redundant like this:
template<class T, class Alloc = std::allocator<T> >
class vector { ... };
But why is this necessary?
In other words, couldn't they have just said:
template<class T>
class allocator { ... };
template<class T, template<class> class Alloc = std::allocator>
class vector { ... };
which is both more elegant, less redundant, and (in some similar situations) potentially safer?
Why did they go the rebind route, which also causes more redundancy (i.e. you have to say T twice)?
(Similar question goes to char_traits and the rest... although they don't all have rebind, they could still benefit from template template parameters.)
Edit:
But this won't work if you need more than 1 template parameter!
Actually, it works very well!
template<unsigned int PoolSize>
struct pool
{
template<class T>
struct allocator
{
T pool[PoolSize];
...
};
};
Now if vector was only defined this way:
template<class T, template<class> class Alloc>
class vector { ... };
Then you could just say:
typedef vector<int, pool<1>::allocator> int_vector;
And it would work perfectly well, without needing you to (redundantly) say int twice.
And a rebind operation inside vector would just become Alloc<Other> instead of Alloc::template rebind<Other>::other.
A quoted text from Foundations of Algorithms in C++11, Volume 1, chap 4, p. 35 :
template <typename T>
struct allocator
{
template <typename U>
using rebind = allocator<U>;
};
sample usage :
allocator<int>::rebind<char> x;
In The C++ Programming Language, 4th edition, section 34.4.1, p. 998, commenting the 'classical' rebind member in default allocator class :
template<typename U>
struct rebind { using other = allocator<U>;};
Bjarne Stroustrup writes this:
The curious rebind template is an archaic alias. It should have been:
template<typename U>
using other = allocator<U>;
However, allocator was defined before such aliases were supported by C++.
But why is this necessary?
What if your allocator class has more than one template argument?
That's pretty much it in terms of why it is generally discouraged to use template template arguments, in favor of using normal template arguments, even if it means a bit of redundancy at the instantiation site. In many cases (however, probably not for allocators), that argument might not always be a class template (e.g., a normal class with template member functions).
You might find it convenient (within the implementation of the container class) to use a template template parameter just because it simplifies some of the internal syntax. However, if the user has a multi-argument class template as an allocator he wants to use, but you require the user to provide an allocator which is a single-argument class template, you will in effect force him to create a wrapper for almost any new context in which he must use that allocator. This not only unscalable, it can also become very inconvenient to do. And, at this point, that solution is far from being the "elegant and less redundant" solution you originally thought it would be. Say you had an allocator with two arguments, which of the following is the easiest for the user?
std::vector<T, my_allocator<T,Arg2> > v1;
std::vector<T, my_allocator_wrapper<Arg2>::template type > v2;
You basically force the user to construct a lot of useless things (wrappers, template aliases, etc.) just to satisfy your implementation's demands. Requiring the author of a custom allocator class to supply a nested rebind template (which is just a trivial template alias) is far easier than all the contortions you require with the alternative approach.
In your approach you are forcing the allocator to be a template with a single parameter, which might not be always the case. In many cases, allocators can be non-template, and the nested rebind can return the same type of the allocator. In other cases the allocator can have extra template arguments. This second case is the case of std::allocator<> which as all templates in the standard library is allowed to have extra template arguments as long as the implementation provides default values. Also note that the existence of rebind is optional in some cases, where allocator_traits can be used to obtain the rebound type.
The standard actually mentions that the nested rebind is actually just a templated typedef:
§17.6.3.5/3
Note A: The member class template rebind in the table above is
effectively a typedef template. [ Note: In general, if the name
Allocator is bound to SomeAllocator<T>, then
Allocator::rebind<U>::other is the same type as SomeAllocator<U>,
where someAllocator<T>::value_type is T and SomeAllocator<U>::value_type is U. — end note ] If Allocator is a class template
instantiation of the form SomeAllocator<T, Args>, where Args is zero
or more type arguments, and Allocator does not supply a rebind member
template, the standard allocator_traits template uses SomeAllocator<U, Args> in place of Allocator:: rebind<U>::other by default. For
allocator types that are not template instantiations of the above
form, no default is provided.
Suppose you want to write a function taking all sorts of vectors.
Then it is much more convenient being able to write
template <class T, class A>
void f (std::vector <T, A> vec) {
// ...
}
than having to write
template <class T, template <class> class A>
void f (std::vector <T, A> vec) {
// ...
}
In most of the cases, such a function does not care about the allocator anyway.
Further note that allocators are not required to be a template. You could write separate classes for particular types that need to be allocated.
An even more convenient way of designing allocators would probably have been
struct MyAllocator {
template <class T>
class Core {
// allocator code here
};
};
Then it would have been possible to write
std::vector <int, MyAllocator> vec;
rather than the somewhat misleading expression
std::vector <int, MyAllocator<int> > vec;
I am not sure whether the above MyAllocator is permitted to be used as an allocator after adding a rebind, i.e. whether the following is a valid allocator class:
struct MyAllocator {
template <class T>
class Core {
// allocator code here
};
template <class T>
struct rebind { using other=Core<T>; };
};

Is there a way to bind a template<template> parameter?

Context
I have a custom comparator that takes another comparator and applies an additional check:
template <template <typename> class Comparator, typename T>
struct SoftOrder : public std::binary_function<T, T, bool> {
bool operator()(const T lhs, const T rhs) const {
return Comparator<T>()(lhs, rhs) && AnotherCheck();
}
};
I have a second class that accepts a comparator, e.g.:
template <template <typename> class Comparator>
class Processor { ... };
It is easy to instantiate a Processor with a standard comparator (e.g. std::less) like so:
Processor<std::less> processor1;
Processor<std::greater> processor2;
However it is not so easy to instantiate with SoftOrder as the compiler correctly complains about the missing second template argument:
Processor<SoftOrder<std::less> > processor3; // <-- Fails to compile
Current Solutions
I have come up with a few solutions prior to posting this question.
First Solution - Lots of Derived Classes
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {};
template <typename T>
struct SoftOrderGreaterThan : public SoftOrder<std::greater, T> {};
The main drawback of this solution is the need to create a new struct every time a new variant is required, e.g.:
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {}; // Never used after the next line.
Processor<SoftOrderLessThan> processor3;
Second Solution - A very specific bind class
template <template <typename> class Comparator>
struct BindToSoftOrder {
template <typename T>
struct type : public SoftOrder<Comparator, T> {};
};
This is slightly better in that we don't need to create the intermediate classes explicitly:
Processor<BindToSoftOrder<std::less>::type> processor3;
The downside is the requirement of a class specialised for this situation which cannot really be generalised by making SoftOrder a template parameter on BindToSoftOrder as this would make it a template<template<template>>> which is not permitted by the standard.
Third Solution - C++11 template aliases
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>;
Nicer than the first option in that it doesn't require the introduction of new classes, however still requires littering the code with this extra code that is only used in passing onwards to another template class:
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>; // Never used again
Processor<SoftOrderLessThan> processor3;
Finally, the question
Is there a generic way to bind my custom comparator to a specific comparator in the following manner?
Processor<SomeCoolMetaTemplateBind<SoftOrder, std::less>::type> processor3;
I believe if all of the template parameters were simple types I could just do something like Processor<boost::mpl::bind<SoftOrder, std::less> >, but the presence of the template type in the template parameter list prevents this from occurring.
An ideal solution would involve C++03, but am happy to hear C++11 solutions as well.
If it's not possible, I hope at least the question was interesting.
Seems like this would work:
template <
template <template <typename> class,class> class U,
template <typename> class X
>
struct SomeCoolMetaTemplateBind {
template <typename T>
struct type : public U<X,T> {
};
};