correct syntax for template - c++

template <typename _Type, typename _Comparator=less<typename _Type::value_type> >
class Myclass
// and then comes the rest of my class
I want to create a specialized template with strings (but also working with other comparator than the default one)
I tried this but it is not compiling.
template <typename _Comparator=less<typename _Type::value_type> >
class Myclass<string>
I know that the next example works but it uses the default comparator I fixed.
template <>
class Myclass<string>

It is not allowed to specify default template arguments in the class template specialization. Use the following syntax to achieve what you want:
template <typename Comparator>
class Myclass<string, Comparator>
{
// ...
};

You can make another default template parameter:
template<class Comparator = other_functor>
class Myclass<string, Comparator> {
};

Remove the =less<typename _Type::value_type> when you declare the specialization.

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 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.

template< template <typename> something_else >, what is this?

I'm just starting learning C++11 and I never saw this syntax in the list of new features:
template <template <typename> class F>
struct fun;
what is it and how does it work?
Note: What you are looking at is an "old" feature, and has been there since long before c++11.
template <template <typename> class F> struct Obj;
In the above Obj is a template only accepting a template-parameter which is also a template[1]; this is most often referred to as a template-template parameter [2].
1) in this specific example it will only accept a template that takes one type-parameter.2) Link to SO question: Template Template Parameters
Imagine that you'd like to have a wrapper around some class template; you don't care which class template this is as long as you can specify a template argument for it.
If so, you can use a template-template parameter as in the below example:
template<template<typename T> class TemplateType>
struct Obj {
TemplateType< int> m1;
TemplateType<float> m2;
};
template<typename T>
struct SomeTemplate { /* ... */ };
Obj<SomeTemplate> foo;
In the above, foo will be a Obj<SomeTemplate> having two members:
SomeTemplate< int> m1
SomeTemplate<float> m2
This should works in C++98 as well. This is a template as an argument from a template. I mean a template class will expected as the argument for F.
Maybe this page will help you: http://www.cprogramming.com/tutorial/templates.html

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>();

How to implement is_stl_vector

I want to specialize a template for STL's vector template arguments. Something like this:
// (1)
template <typename T>
class A
{
...
};
// (2)
template <>
class A<std::vector<> >
{
...
};
I don't care what is the type of the vector element. I would like to use it as follows:
A<int> a1; // Will use the general specialization
A<std::vector<int> > a2; // Will use the second specialization
In general I've been trying to define something similar to boost's type traits. Something like
template <class T>
struct is_stl_vector
{
// Will be true if T is a vector, false otherwise
static const bool value = ...;
};
I cannot use template template (I think so) because it should compile for non-template types too. Is it possible at all?
You can simply specialize like this:
// (2)
template <typename T, typename Alloc>
struct A<std::vector<T, Alloc> >
{...};
The specialization goes like this:
// (2)
template <class T, class U>
class A<std::vector<T, U> >
{
...
};
Note that it is not guaranteed to work (and there si no other way that's guaranteed to work), because the template parameter count of std::vector may vary across implementations. In C++0x, this should be solvable using parameter packs.