Passing partially specialized template as a template parameter - c++

I have a class template, expecting some other template as a parameter:
template<
class Key,
template <typename K,template <typename T> class Allocator> class Policy
>
class container {
Policy<Key,Allocator>* _policy;
//some code here
};
and usually i use it with the policy class like this:
template <class Key,template <typename T> class Allocator> class policy {
//some code
};
but what if i have to pass additional template parameter to policy class? Something like:
template <time_t Age,class Key,template <typename T> class Allocator> class policy_3 {
//some code
};
What can i do, to allow users of that class, pass the Age paratemeter without touching others? For example:
typedef container<key_type,policy_3<100500> > containerWithAge;

You have two options: binding, and rebinding.
In binding, you adapt the ternary policy into a binary one, as expected by the template-template parameter Policy:
template <typename Key, template <typename T> class Allocator>
struct policy_3_100500 : ternary_policy<100500,Key,Allocator> {};
and use policy_3_100500 instead of policy_3<100500>.
To be closer to the syntax you're shooting for, you can use a nested class:
template <time_t Age>
struct policy_3 {
template <typename Key, template <typename T> class Allocator>
struct type : ternary_policy<Age,Key,Allocator> {};
};
and use policy_3<100500>::type instead of policy_3<100500>.
The only way to get exactly the syntax you want is to move the ::type into the class using the policy. That's the second option: rebinding (this is also used in std::allocator, btw). In this case, you pass the Policy as a normal template parameter, and assume a template metafunction, say bind, to exist:
template <time_t Age>
struct policy_3 {
template <typename Key, template <typename T> class Allocator>
struct bind : ternary_policy<Age,Key,Allocator> {};
};
While structually identical to the second option, the difference lies in who calls bind: In the first option (binding), it's the user of the policy class (by passing policy<100500>::type explicitly). Here, it's the class using the policy:
template <typename Key, typename Policy>
struct container {
typename Policy::template bind<Key,std::allocator<Key>> * _policy;
// ...
}:
As a general note, Policy classes are not usually passed as template-template arguments, but as normal template arguments (precisely because they may have a varying number of arguments themselves). The classes using the policy then assume a certain inner structure (typedefs, functions, meta functions, constants) to be present in the policy, of which bind is just an example.

Related

Template class specialization with std::enable_if and a concrete type

I have JsonFormatter template class that is specialized for different types like arithmetic etc... in the following way:
template <class T, typename Enable = void>
class JsonFormatter;
template <class T>
class JsonFormatter<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
{
};
it is not clear how to specialize it for a concrete type like std::string, for example? My first idea was something like this:
template <>
class JsonFormatter<std::string, std::true_type>
{
};
but this does not compile. When I use
JsonFormatter<std::string>
I get
"undefined class 'JsonFormatter<std::string,void>'"
The important point is that the specialization has to match the primary. In this case, the primary is set up such that the 2nd template parameter is going to be void - it's not intended to be provided by the user, it's just there to enable people to use enable_if.
std::true_type doesn't match void, which is why it doesn't work. When the user writes JsonFormatter<std::string>, the default argument will get instantiated as void - so they're looking for the specialization JsonFormatter<std::string, void>... which isn't what you provided.
You want:
template <>
class JsonFormatter<std::string, void>
{ };
Or even just:
template <>
class JsonFormatter<std::string>
{ };
Since the default argument will get filled in just fine.
This is how you specialize the template:
template <>
class JsonFormatter<std::string, void>
{
};
You can also use std::enable_if, but I don't recommend it since it a simple specialization is much easier. std::enable_if works correctly with SFINAE only. So it needs to depend on a template parameter:
template <class T>
class JsonFormatter<T, std::enable_if_t<std::is_same_v<T, std::string>>>
{
};
it is not clear how to specialize it for a concrete type like std::string, for example?
Have you tried simply with
template <>
class JsonFormatter<std::string>
{
};
?
Should works.
The second template parameter become void according the dafault value defined in the main version.

Template parameter for a class which is also a template parameter

I try to do the following, I think the example should be self-explaining:
template <class CLASS, class PARAM>
void call(){
CLASS<PARAM>::do_something();
}
On the angular brackets between CLASS and PARAM on line 3, the compiler says:
error: expected unqualified-id
Can I fix this problem or is it not allowed what I try to do?
template <
template <typename T> class CLASS,
typename PARAM>
void call()
{
CLASS<PARAM>::do_something();
}
The template parameter CLASS is declared to be a class, or also a typename, I.e. the name of a type.
template<typename X> struct A;
Here A isn't a type, it's a template. To obtain a type, you need to "apply"(*) the template: A<int>.
If you write CLASS<PARAM>, you're trying to apply a type to a type. This won't work. It's like trying to call a value 42(parameter), only on the type level.
So you need to specify that CLASS is something which can be applied, that it's a template:
template <typename T> class CLASS
So, for reference, the complete solution is:
template <template <typename T> class CLASS, class PARAM>
void call(){
CLASS<PARAM>::do_something();
}
(*) A template is a function on type level: It takes one or more types, and returns a new type.
In addition to the answers given by #DanielJour and #Nasser, I want to mention that the name T of the type name for the template template parameter CLASS can be omitted, because it is not used. So, the condensed solution would look like this:
template <template <typename> class CLASS, typename PARAM>
void call()
{
CLASS<PARAM>::do_something();
}
Reference: Template Template Parameters.

Template template parameter with default values unknown

I have a template function that takes a container as a parameter
(I use this function for both vector, set, map so trying to avoid it would cost a lot of code copying)
so naturally I declared it as:
template<template<class T, class Allocator = std::allocator<T>> class
Container> Container<std::weak_ptr<A>>* Foo() {...}
Note that the return value of Foo uses the default parameter of the container.
When I use the function with vector, list or set it works just fine;
the problem I have is when I try to use this template with a map container with the comparator and value type fixed (which is defined as MapToValue<ValueType>::FromKey with A and Comparator<Key> already defined):
template<class Value> class MapToValue {
template<class Key, class Allocator = std::allocator<std::pair<const
Key, Value>>> FromKey : public std::map<Key, Value, Comparator<Key>,
Allocator> {...}
In this case the default value of the allocator is diffrent then the one in the definition of Foo - std::allocator<std::pair<_Ty, std::string>> vs. std::allocator<_Ty>.
Long story short, I need that to send to Foo a container with a second parameter that can be defaulted WITHOUT knowing what this default type would be (so this function template can be used for both map, vector or basically any other container). Is this possible?
EDIT: I cannot use C++11 in any way, the compiler is gcc 4.1.2 (out of my control)
In c++11 you can take any template as template argument:
template<template <class ...> class Container>
Container<std::weak_ptr<A>>* Foo() {...}
There's a misunderstanding here of how template template parameters operate. This declaration:
template<template<class T, class Allocator = std::allocator<T>> class Container>
Container<std::weak_ptr<A>>* Foo() {...}
Is just an overly verbose version of this declaration:
template < template <class, class> class Container>
Container<std::weak_ptr<A>>* Foo() {...}
(What is A btw?)
It doesn't matter what the names or defaults of the types are that Container takes - Foo is simply templated on some class template that takes two template type arguments. That works with vector because it is a class template that takes two template type arguments:
template<
class T,
class Allocator = std::allocator<T>
> class vector;
It does not work with map because that one takes four template type arguments:
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
In C++11, you can generalize your function to have a template template argument take an arbitrary number of template type arguments:
template < template <class...> class Container>
Container<std::weak_ptr<A>>* Foo() {...}
Though, however, this is never going to work as some container types can't be constructed with only a single template argument (e.g. map).
I found a solution, it isn't elegant but it works:
Sending to Foo another template argument that would be the way to deafault the Allocator:
template<template<typename> class DefaultAllocator, template<typename T,
typename Allocator = DefaultAllocator<T>> class Container>
Container<std::weak_ptr<A>>* Foo() {...}
This way I send Foo<std::allocator,std::vector> all the same.
Also by creating some wrapper template<class T> class MapAllocatorWrapper : std::allocator<std::pair<T,std::string>>, I can send Foo<MapAllocatorWrapper, MapToType<std::string>::FromKey after slight adjustments.

Using template class from template class in template method

I need to use a template class which is defined in another template class as parameter of another template as return value in template method. I know it sounds complicated, code below explains it better. Problem is that the code cannot be compiled, it ends with following error:
type/value mismatch at argument 2 in template parameter list for 'template<class T, template<class> class Policy> class Result'
expected a class template, got 'CDummy<T2>::Policy2'
but I'm pretty sure that given class fulfills needs. Problem is that the method, which uses it, is template too and so compiler does not know what exactly CDummy<T2>::Policy2 is. If the Policy2 would not be template, but regular class or if I could fill its argument, I would use typename which would tell the compiler not to worry about it, but how can this be done with template?
// I cannot change this interface - it's given by a library
template <class T, template <class> class Policy>
class Result : public Policy<T>
{
T data;
};
template <class T>
class Policy1
{
};
// I use this for allowing Policy2 to change behaviour according Dummy
// while it keeps template interface for class above
template <class Dummy>
class CDummy
{
public:
template <class T>
class Policy2 : public Policy1<T>
{
};
};
// Both variables are created ok
Result<int, Policy1 > var1;
Result<int, CDummy<float>::Policy2 > var2;
// This is ok, too
template <class T>
Result<T, Policy1 > calc1()
{
return Result<int, Policy1>();
}
// But this ends with the error:
// type/value mismatch at argument 2 in template parameter list for 'template<class T, template<class> class Policy> class Result'
// expected a class template, got 'CDummy<T2>::Policy2'
template <class T1, class T2>
Result<T1, CDummy<T2>::Policy2 > calc2() // <-- Here is the generated error
{
typedef typename DummyTypedef CDummy<T2>;
return Result<T1, DummyTypedef::Policy2>();
}
Notes:
I use gcc 4.7.3 32bit in GNU/Linux Ubuntu 13.04. 32 bit.
For various reasons, I cannot use C++11 standard (yet) and so I cannot use template typedefs
I believe that the name CDummy<T2>::Policy2 is a dependent name in that context and that you should use the template keyword to inform the compiler that it is indeed a template.
template <class T1, class T2>
Result<T1, CDummy<T2>::template Policy2 > calc2() // <-- Here is the generated error
// ^^^^^^^^
additionally the implementation of that same function seems to be wrong also. The order of typedefs is original name, new name, and CDummy<T2> is known to be a type (i.e. there is no need for the typename):
typedef CDummy<T2> DummyTypedef;
The return statement would then be:
return Result<T1, DummyTypedef::template Policy2>();

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> {
};
};