How to implement is_stl_vector - c++

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.

Related

How to use member type of a template class without specifying unnecessary template parameters?

I am trying to use a member type of a template class, which does not depend on any template parameters of the template class. I would like to keep the type as the member type due to its logic, but I do not want to specify the unnecessary template parameters of the class whenever I want to use the member type outside the class.
Consider the following:
class Dummy { };
// Template class
template<typename T>
class A {
public:
template<typename T2>
class MemberType : public T2 {
public:
T2 t2;
};
};
int main()
{
typename A<Dummy>::template MemberType<Dummy> m1; // okay
typename A::template MemberType<Dummy> m2; // not okay!
return 0;
}
I got the following compiler error when I try to compile using g++:
error: ‘template<class T> class A’ used without template parameters
typename A::template MemberType<Dummy> m2; // not okay!
Is there any workaround for this?
I am trying to use a member type of a template class, which does not
depend on any template parameters of the template class.
As a nested type within class A<T>, MemberType does depend on the template parameter T.
i.e. A<T>::MemberType<T2> and A<U>::MemberType<T2> are distinct classes.
What you want to do is not possible. A template is just a template. There is very little you can do with it before actually instantiating it for a concrete type. There could be a specialization for A that has no nested MemberType at all.
I would like to keep the type as the member type due to its logic,
[...]
...but it seems the logic is something else: The MemberType does not depend on A, hence it should not be part of a template that depends on A.
Sloppy speaking template<typename T> can be read as "everything that follows depends on T". Even if you think it does not, there could always be a specialization that changes anything inside A. If you want MemberType to not depend on T then declare it outside A.
Everything in a template is dependent on the parameter(s) - meaning a template-specialization might not even have class MemberType.
But you can make a default parameter - you still need to write <> though (but you can omit template usually - even typename, but I left that):
class Dummy { };
// Template class
template <class T = void>
class A {
public:
template<typename T2>
class MemberType : public T2 {
public:
T2 t2;
};
};
int main()
{
typename A<Dummy>::MemberType<Dummy> m1; // okay
typename A<>::MemberType<Dummy> m2; // also ok
return 0;
}
As others have pointed out, this somewhat looks like an anti-pattern though - since the inner type is not dependent on the parameter of the outer template class.
Is there any workaround for this?
MemberType is a type dependent from a template parameter so, necessarily, you have to pass through the containing template a template parameter to define it
typename A<SomeType>::template MemberType<AnotherType> m2;
Taking in count that your not interested in external SomeType parameter, the best workaround I can imagine is the use of a using as follows (or something similar)
template <typename T>
using MemberType_t = typename A<T>::template MemberType<T>;
to reduce typewriting.
The following is a full compiling simplified example
#include <type_traits>
class Dummy { };
template <typename>
struct A
{
template <typename T2>
struct MemberType : public T2
{ T2 t2; };
};
template <typename T>
using MemberType_t = typename A<T>::template MemberType<T>;
int main ()
{
typename A<Dummy>::template MemberType<Dummy> m1;
MemberType_t<Dummy> m2; // compile
static_assert( std::is_same<decltype(m1), decltype(m2)>::value, "!" );
}

signed/unsigned trait programming

I'm starting to learn about traits and templates in c++. What I'm wondering is is it possible to create templates for signed/unsigned integral types. The idea is that the normal class would (probably) be implemented for singed integer types, and the variation for unsigned integer types. I tried:
template <typename T>
class FXP<T>
{ ... };
template <typename T>
class FXP<unsigned T>
{ ... };
but this does not compile.
I even came across:
std::is_integral
std::is_signed
std::is_unsigned
So, how do I put these in action to define a class that only supports these two variants?
In this case, there's a few ways to go about it, but my favorite for cases where there's a limited number of variants (e.g., a boolean or two saying which way it should behave), partial specialization of a template is usually the best way to go:
// Original implementation with default boolean for the variation type
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
class FXP {
// default implementation here
};
Your next step is to then provide a partial specialization that takes the typename T, but only works for a specific variant of the template parameters (e.g. true or false).
template <typename T>
class FXP<T, false> {
// partial specialization when is_unsigned becomes false
};
template <typename T>
class FXP<T, true> {
// partial specialization when is_unsigned becomes true
};
In this case, if you write a default implementation, you only need to make a specialization for the case that's non-default (like the true case).
Here's an example, where the default case gets overridden by a specialized template parameter:
http://coliru.stacked-crooked.com/a/bc761b7b44b0d452
Note that this is better only for smaller cases. If you need complex tests, you're better off using std::enable_if and some more complicated template parameters (like in DyP's answer).
Good luck!
With an additional template parameter:
#include <iostream>
#include <type_traits>
template <typename T, class X = void>
struct FXP
{
// possibly disallow using this primary template:
// static_assert(not std::is_same<X, X>{},
// "Error: type neither signed nor unsigned");
void print() { std::cout << "non-specialized\n"; }
};
template <typename T>
struct FXP< T, typename std::enable_if<std::is_signed<T>{}>::type >
{ void print() { std::cout << "signed\n"; } };
template <typename T>
struct FXP< T, typename std::enable_if<std::is_unsigned<T>{}>::type >
{ void print() { std::cout << "unsigned\n"; } };
struct foo {};
int main()
{
FXP<foo>().print();
FXP<int>().print();
FXP<unsigned int>().print();
}

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

How to do a partial template specialization on a nested type?

I have a templated class Converter, and I'd like to do a partial specialization. The tricky part is I'd like to specialize it to MyFoo::Vec where MyFoo again can be specialized as a template parameter. If that sounds confusing, maybe the code itself makes it clearer:
#include <iostream>
#include <vector>
template<class To>
struct Converter {
Converter(int from, To& to) {
to = To(from);
}
};
template<class T>
struct Foo {
typedef std::vector<T> Vec;
Vec vec;
};
// Template specialization: Convert from 'From' to 'MyFoo::Vec':
template<class MyFoo>
struct Converter<typename MyFoo::Vec > { // Error: template parameters not
// used in partial specialization
Converter(int from, typename MyFoo::Vec& to) {
to.push_back(typename MyFoo::Vec::value_type(from));
}
};
int main() {
Foo<float> myfoo;
Converter<Foo<float> > converter(2, myfoo.vec);
}
This is just a mini example derived from my actual code. This question is not about how useful such a converter is; I'm just interested in getting the syntax right given that I need such a converter and its specialization.
It cannot be done directly. Consider that it is impossible to go from the nested type to the enclosing type for two reasons: first, the mapping might not be unique (multiple Foo might have the same nested Vec type) and even if it was the compiler would have to test all existing types (i.e. it cannot infer from the instantiation).
What you want to do can actually be done with SFINAE (untested code, you can read more here):
template <typename T, typename V = void>
struct Converter {}; // Default implementation
template <typename T>
struct Converter<T, T::Vec> {}; // specific if has nested Vec

Default values in templates with template arguments ( C++ )

Assume I have a template (called ExampleTemplate) that takes two arguments: a container type (e.g. list, vector) and a contained type (e.g. float, bool, etc). Since containers are in fact templates, this template has a template param. This is what I had to write:
#include <vector>
#include <list>
using namespace std;
template < template <class,class> class C, typename T>
class ExampleTemplate {
C<T,allocator<T> > items;
public:
....
};
main()
{
ExampleTemplate<list,int> a;
ExampleTemplate<vector,float> b;
}
You may ask what is the "allocator" thing about. Well, Initially, I tried the obvious thing...
template < template <class> class C, typename T>
class ExampleTemplate {
C<T> items;
};
...but I unfortunately found out that the default argument of the allocator...
vector<T, Alloc>
list<T, Alloc>
etc
...had to be explicitely "reserved" in the template declaration.
This, as you can see, makes the code uglier, and forces me to reproduce the default values of the template arguments (in this case, the allocator).
Which is BAD.
EDIT: The question is not about the specific problem of containers - it is about "Default values in templates with template arguments", and the above is just an example. Answers depending on the knowledge that STL containers have a "::value_type" are not what I am after. Think of the generic problem: if I need to use a template argument C in a template ExampleTemplate, then in the body of ExampleTemplate, do I have to reproduce the default arguments of C when I use it? If I have to, doesn't that introduce unnecessary repetition and other problems (in this case, where C is an STL container, portability issues - e.g. "allocator" )?
Perhaps you'd prefer this:
#include <vector>
#include <list>
using namespace std;
template <class Container>
class ForExamplePurposes {
typedef typename Container::value_type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
}
This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.
Perhaps using the type traits idiom can give you a way out:
#include <vector>
#include <list>
using namespace std;
struct MyFunkyContainer
{
typedef int funky_type;
// ... rest of custom container declaration
};
// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
typedef typename Container::value_type type;
};
// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
typedef MyFunkyContainer::funky_type type;
};
template <class Container>
class ForExamplePurposes {
typedef typename ValueTypeOf<Container>::type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
ForExamplePurposes< MyFunkyContainer > c;
}
Someone who wants to use ForExamplePurposes with a non-STL-compliant container would need to specialize the ValueTypeOf traits class.
I would propose to create adapters.
Your class should be created with the exact level of personalization that is required by the class:
template <template <class> C, template T>
class Example
{
typedef T Type;
typedef C<T> Container;
};
EDIT: attempting to provide more is nice, but doomed to fail, look at the various expansions:
std::vector<T>: std::vector<T, std::allocator<T>>
std::stack<T>: std::stack<T, std::deque<T>>
std::set<T>: std::set<T, std::less<T>, std::allocator<T>>
The second is an adapter, and so does not take an allocator, and the third does not have the same arity. You need therefore to put the onus on the user.
If a user wishes to use it with a type that does not respect the expressed arity, then the simplest way for him is to provide (locally) an adapter:
template <typename T>
using Vector = std::vector<T>; // C++0x
Example<Vector, bool> example;
I am wondering about the use of parameter packs (variadic templates) here... I don't know if declaring C as template <class...> C would do the trick or if the compiler would require a variadic class then.
You have to give the full template signature, including default parameters, if you want to be able to use the template template parameter the usual way.
template <typename T, template <class U, class V = allocator<U> > class C>
class ExampleTemplate {
C<T> items;
public:
....
};
If you want to handle other containers that the one from the STL, you can delegate container construction to a helper.
// Other specialization failed. Instantiate a std::vector.
template <typename T, typename C>
struct make_container_
{
typedef std::vector<T> result;
};
// STL containers
template <typename T, template <class U, class V = allocator<U> > class C>
struct make_container_<T,C>
{
typedef C<T> result;
};
// Other specializations
...
template <typename T, typename C>
class ExampleTemplate {
make_container_<T,C>::result items;
public:
....
};
I think, it is required to reproduce all template parameters, even default. Note, that Standard itself does not use template template parameters for containter adaptors, and prefers to use regular template parameters:
template < class T , class Container = deque <T > > class queue { ... };
template < class T , class Container = vector <T>, class Compare = less < typename Container :: value_type > > class priority_queue { ... };
The following code will allow you to do something like you're asking for. Of course, this won't work with standard containers, since this has to already be part of the template class that's being passed into the template.
/* Allows you to create template classes that allow users to specify only some
* of the default parameters, and some not.
*
* Example:
* template <typename A = use_default, typename B = use_default>
* class foo
* {
* typedef use_default_param<A, int> a_type;
* typedef use_default_param<B, double> b_type;
* ...
* };
*
* foo<use_default, bool> x;
* foo<char, use_default> y;
*/
struct use_default;
template<class param, class default_type>
struct default_param
{
typedef param type;
};
template<class default_type>
struct default_param<use_default, default_type>
{
typedef default_type type;
};
But I don't really think this is what you're looking for. What you're doing with the containers is unlikely to be applicable to arbitrary containers as many of them will have the problem you're having with multiple default parameters with non-obvious types as defaults.
As the question exactly described the problem I had in my code (--I'm using Visual Studio 2015), I figured out an alternative solution which I wanted to share.
The idea is the following: instead of passing a template template parameter to the ExampleTemplate class template, one can also pass a normal typename which contains a type DummyType as dummy parameter, say std::vector<DummyType>.
Then, inside the class, one replace this dummy parameter by something reasonable. For replacement of the typethe following helper classes can be used:
// this is simply the replacement for a normal type:
// it takes a type T, and possibly replaces it with ReplaceByType
template<typename T, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type
{
using type = std::conditional_t<std::is_same<T, ReplaceWhatType>::value, ReplaceByType, T>;
};
// this sets up the recursion, such that replacement also happens
// in contained nested types
// example: in "std::vector<T, allocator<T> >", both T's are replaced
template<template<typename ...> class C, typename ... Args, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type<C<Args ...>, ReplaceWhatType, ReplaceByType>
{
using type = C<typename replace_type<Args, ReplaceWhatType, ReplaceByType>::type ...>;
};
// an alias for convenience
template<typename ... Args>
using replace_type_t = typename replace_type<Args ...>::type;
Note the recursive step in replace_type, which takes care that types nested in other classes are replaced as well -- with this, for example, in std::vector<T, allocator<T> >, both T's are replaced and not only the first one. The same goes for more than one nesting hierarchy.
Next, you can use this in your ExampleTemplate-class,
struct DummyType {};
template <typename C, typename T>
struct ExampleTemplate
{
replace_type_t<C, DummyType, T> items;
};
and call it via
int main()
{
ExampleTemplate<std::vector<DummyType>, float> a;
a.items.push_back(1.0);
//a.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::list<DummyType>, float> b;
b.items.push_back(1.0);
//b.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::map<int, DummyType>, float> c;
c.items[0]=1.0;
//c.items[0]="Hello"; // prints an error message which shows that DummyType is replaced correctly
}
DEMO
Beside the not-that-nice syntac, this has the advantage that
It works with any number of default template parameters -- for instance, consider the case with std::map in the example.
There is no need to explicitly specify any default template parameters whatsoever.
It can be easily extended to more dummy parameters (whereas then it probably should not be called by users ...).
By the way: Instead of the dummy type you can also use the std::placeholder's ... just realized that it might be a bit nicer.