from https://github.com/wjakob/tbb/blob/master/include/tbb/tbb_allocator.h#L150
template <typename T, template<typename X> class Allocator = tbb_allocator>
class zero_allocator : public Allocator<T>
{...}
what I understand is that this is a definition for a new class, that inherits from the Allocator type visible in that translation unit .
the part that I don't get is template<typename X> class Allocator = tbb_allocator .
according to the tbb docs the zero_allocator takes 2 inputs, the type T and how many objects of type T you need to allocate . the zero_allocator also inheriths from the tbb_allocator which in turns defaults to a "standard" malloc/free behaviour if TBB is not present when linking .
I still don't think I get that syntax, especially the template<typename X> class Allocator part .
Can you explain this syntax and what is achieving ?
template <typename T, template<typename X> class Allocator = tbb_allocator>
class zero_allocator : public Allocator<T>
{...}
What we have:
template starts declaration of a template
it is followed by the template parameter list:
<typename T, template<typename X> class Allocator = tbb_allocator>
The first template parameter is "some type" T
the next one is not a type, it is a template itself.
template<typename X> class Allocator
So the template class zero_allocator needs to get instantiated with first
parameter is any type T and with second parameter a template which itself takes on template parameter X must be given.
In addition, the second template parameter for zero_allocator can be left, in this case for Allocator parameter the template tbb_allocator is used.
Here a full compileable example:
template <typename Y>
class ExampleTemplate {};
// and the one which is used as the default
template <typename Y>
class tbb_allocator {};
template <typename T, template<typename X> class Allocator = tbb_allocator>
class zero_allocator : public Allocator<T>
{
// Lets use the type T:
T some_var; // in our example, this will be "int some_var"
// and here we use the Template Template thing...
Allocator<float> some_allocator;
};
int main()
{
zero_allocator< int, ExampleTemplate > za;
}
Related
Say I have a simple template like this:
template<typename T>
class A {};
And I want to specify that the type-parameter T is of some unrelated type X<U> where U is not known (or unspecifyable).
Is there a way how to express that as a concept?
Is there a way how to express that as a concept?
You don't need a concept, class template specialization works just fine in your case.
As an example, you can do this:
template<typename T>
class A;
template<typename U>
class A<X<U>> { /* ... */ };
This way, unless A is instantiated with a type of the form X<U> (where U is unknown), you'll get a compile-time error because the primary template isn't defined. In other terms, it won't work for all the types but X<U> (for each U), where the latter matches the class template specialization that has a proper definition.
Note that I assumed X is a known type. That's not clear from your question.
Anyway, if it's not and you want to accept types of the form X<U> for each X and each U, you can still do this:
template<typename T>
class A;
template<template<typename> class X, typename U>
class A<X<U>> { /* ... */ };
As a minimal, working example:
template<typename>
struct S {};
template<typename>
class A;
template<typename U>
class A<S<U>> {};
int main() {
A<S<int>> aSInt;
A<S<double>> aSDouble;
// A<char> aChar;
}
Both A<S<int>> and A<S<double>> are fine and the example compiles. If you toggle the comment, it won't compile anymore for A<char> isn't defined at all.
As a side note, if you don't want to use class template specialization and you want to simulate concepts (remember that they are not part of the standard yet and they won't be at least until 2020), you can do something like this:
#include<type_traits>
template<typename>
struct X {};
template<typename>
struct is_xu: std::false_type {};
template<typename U>
struct is_xu<X<U>>: std::true_type {};
template<typename T>
struct A {
static_assert(is_xu<T>::value, "!");
// ...
};
int main() {
A<X<int>> aXInt;
A<X<double>> aXDouble;
// A<char> aChar;
}
That is, given a generic type T, static assert its actual type by means of another structure (is_xu in the example) that verifies if T is of the form X<U> (for each U) or not.
My two cents: the class template specialization is easier to read and understand at a glance.
template <typename T, template <typename> class C>
concept bool Template = requires (T t) { {t} -> C<auto>; };
Now given a class template:
template <typename T>
struct X {};
a type template parameter can be constrained using:
template <typename T> requires Template<T, X>
class A {};
or:
template <Template<X> T>
class A {};
DEMO
This will work also for types derived from X<U>.
I have some problem. What is meaning next code?
template<typename>
struct function_traits; // (1)
template<typename ClassType,
typename ReturnType,
typename... Arguments>
struct function_traits<ReturnType(ClassType::*)(Arguments...) const> { // (2)
...
};
template<typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};
// (3) Why here inheritance?
Thanks!
It's understandable that you find this a mystery. Most of us do at the beginning.
First:
template<typename>
struct function_traits; // (1)
This declares the general form of a template class which has one template parameter, which is a type (class X, struct Y, int, float, std::string, whatever). Note that at present the template is declared, but no classes can be instantiated from it, because the template has no specialisations. Not even a default one.
Second:
template<typename ClassType,
typename ReturnType,
typename... Arguments>
struct function_traits<ReturnType(ClassType::*)(Arguments...) const> { // (2)
...
using result_type = ReturnType; // capture the template type into a typedef in the class namespace
};
This defines a partial specialisation of the template function_traits<typename T> where T is any member function pointer of any class which returns any return type and takes any number of arguments. Because ReturnType has been assigned a template parameter, it means that the definition of this class is allowed to refer to it as a type, thus deducing the result_type of the member function.
However, at this stage the specialisation is not useful because a caller would need to specify the complete function pointer at the call site, like this: function_traits<&SomeClass::someFunction> and dealing with overloads would be tricky.
Now the third part makes an 'interface' specialisation which says that for any class T, function_traits<T> shall be derived from function_traits<&T::operator()>.
template<typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};
// (3) Why here inheritance?
Because there is such a specific match in the template expansion, it will only be expanded for types that have a call operator (operator()). The base class is providing the return type, from the second specialisation, so this template is able to capture the return type of any type which has a call operator. Because this class is derived from the actual class that captures the return type, result_type is also part of this class's scope.
now we can write:
struct Foo {
int operator()();
};
using foo_ret = function_traits<Foo>::result_type;
And foo_ret will be int.
Still confused? Welcome to your first 6 months of template programming.
How can I specialize a class template so that the template parameters can be of type : a pointer to a particular class or a pointer to the derived class of that particular type? Is it possible to do it without using Boost?
Possible Duplicate of: C++ templates that accept only certain types
I just wanted to know whether the answer is same even if I am using a pointer to the instances .
You could specialize your class for pointers and then use std::is_base_of with a static_assert:
template <typename T>
class foo;
template <typename T>
class foo<T*>
{
static_assert(std::is_base_of<Base, T>::value, "Type is not a pointer to type derived from Base");
};
See it in action. Both std::is_base_of and static_assert are C++11 features so no Boost is required.
If for some reason you don't like static_assert, you could do it the enable_if way:
template <typename T, typename Enable = void>
class foo;
template <typename T>
class foo<T*, typename std::enable_if<is_base_of<Base, T>::value>::type>
{
// ...
};
A technique for having specializations based on some predicate instead of a pattern is to use an extra defaulted parameter.
template <typename T, bool = predicate<T>::value>
class foo {
// here is the primary template
};
template <typename T>
class foo<T, true> {
// here is the specialization for when the predicate is true
};
All you need is a proper predicate. In this case, std::is_base_of seems to fit. There is a boost implementation of it too.
I can't for the life of me get this to work.
I have an existing template:
template <class T>
class MyTemplate;
Now I want to specialize it, but for a class T that's a template--without further specializing the second template, for example:
template <>
template <class T>
class MyTemplate<vector> { /*...*/ };
But this, and various other syntaxes I've tried don't seem to compile. What's the syntax for this? Or is it even possible? If not, are there possible alternatives for MyTemplate so that I could handle, say, a generalized specialization for both vector and map?
I think you're looking for this:
template<typename T>
class MyTemplate {...}
template<typename T>
class MyTemplate<vector<T> > {...}
Above, the partial specialization is used when you make a MyTemplate<vector<int> > x; and T is int.
The proper syntax is :
template < typename T>
class MyTemplate<vector<T> > { /*...*/ };
more generally
template<typename A, typename B> class MyTemplate;
template<typename C, typename D> class SomeTemplate;
template<typename A, typename C>
class MyTemplate<A, SomeTemplate<C,A> > { /* ... */ };
A template can be defined either in terms of:
non-type parameters (constants)
type parameters
template parameters
once it has been so defined, any specialization must respect the kind of the parameter.
Therefore, if you want to specialize for a vector (which is a template) where a type parameter is expected, you need to spell out the parameters of the vector to create a (templated) type parameter:
template <typename T, typename Alloc>
class MyTemplate < std::vector<T, Alloc> > {
};
Similarly for map, though there are more parameters:
template <typename K, typename V, typename C, typename A>
class MyTemplate < std::map<K, V, C, A> > {
};
and here you go :)
I'm not sure about the syntax for defining a template for a class. You need to look that up. However defining the template is not the catch all. You need to write the class definition for each template. For example if you have an class define to do talking 1 argument of type x, and taking 2 arguments of type y, or etc... then you need a class to handle it. Same as function overloading . You have the same function name but each takes different arguments. You write a function for each. And that call picks the right function based on the argument list.
So a class that ... will sort different objects by defining for each type.
template <
typename T,
template <class> class OwnershipPolicy = RefCounted, #1
class ConversionPolicy = DisallowConversion, #2
template <class> class CheckingPolicy = AssertCheck,
template <class> class StoragePolicy = DefaultSPStorage
>
class SmartPtr;
Q1> What is the syntax for the line #1
template <class> class OwnershipPolicy = RefCounted,
why it doesn't provide a parameter such as follows?
template <class T2> class OwnershipPolicy = RefCounted,
Q2> What is the difference between #1 and #2?
template <class> class OwnershipPolicy = RefCounted,
class ConversionPolicy = DisallowConversion,
Why one of these line have template<class> and the other doesn't?
template <class> class OwnershipPolicy is a template template argument. I.e. OwnershipPolicy is expected to be a template taking one (and only one) type argument. There's no name for that argument, because it's not needed, and you wouldn't be able to use it for anything anyway.
class ConversionPolicy is equivalent to typename ConversionPolicy, i.e. any ordinary type argument.
The difference lies in how you use it. For template template arguments, you provide only name of the template, which you can later use to instantiate concrete types. For typename, you need a concrete type:
template <typename A, template <typename> class B>
struct foo {};
template <typename T>
struct x {};
struct y {};
template <typename T, typename U>
struct z {};
// both of these are valid:
foo<x<int>, x> a;
foo<y, x> b;
// these are not:
foo<y, x<int>> c;
foo<y, y> d;
foo<y, z> e; // z has two template arguments, B must have only one
Worth noting that this idiom is called "policy-based design".