How to specialize a class template for vector? - c++

I am a bit confused about the syntax for template parameters...
How do i specalize this template:
template <typename T> class MyTemplate{
public:
void doSomething(T){}
};
for std::vectors, i.e. I would to write something like
template <std::vector<typename T> > class MyTemplate{
public:
void doSomethingElse(std::vector<T>){}
};
to make the class behave differently, depending on whether the template parameter is just any type T or a vector.

Like this:
template <typename T>
class MyTemplate<std::vector<T> > {
...
};

Related

Remove redundant template types

I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};

C++ pointer template specialization

I'm trying to design a template class of type T* which is declared as follows:
template <class T>
class StructParamPublic<T*>
{
.....
protected:
T* m_pData;
};
which can be used for creating a struct like this
StructParamPublic <FloatArrayStruct*> m_pFloatArray;
where
FloatArrayStruct
{
float* pData;
size_t arraySize;
};
However, when I compile this I'm getting an error that says StructParamPublic is not a template type.
If I define the following template class
template <class T>
class StructParamPublic
{
.....
protected:
T m_Data;
};
then this error goes away.
For some design consideration I don't want to add the second definition to the framework.
My solution was to come up with something like this
template <class T>
class StructParamPublic
{
.....
protected:
T* m_pData;
};
and it compiled fine.
So my question: Is template <class T> class StructParamPublic some kind of 'base template class' and template <class T>class StructParamPublic<T*>
some sort of derivation of that class?
template <class T> class StructParamPublic<T*>;
is a specialization of
template <class T> class StructParamPublic;
So for your problem, you have several possibilities:
(partial) specialization
template <class T> class StructParamPublic;
template <class T>
class StructParamPublic<T*>
{
// code
protected:
T* m_pData;
};
StructParamPublic<int> would lead to an error of undefined class.
or static_assert
template <class T>
class StructParamPublic
{
static_assert(std::is_pointer<T>::type, "type should be a pointer type");
using value_type = typename std::remove_pointer<T>::type;
// code
protected:
T m_pData; // or value_type* m_pData;
};
StructParamPublic<int> would lead to an clean error thanks to static_assert.
or change meaning of your parameter as your solution.
template <class T>
class StructParamPublic
{
.....
protected:
T* m_pData;
};
StructParamPublic<int> is used here whereas previous solution requires StructParamPublic<int*>.
You don't need to define the second class template. You can just use a forward declaration.
template <class T> class StructParamPublic;
and then you can use
template <class T>
class StructParamPublic<T*>
{
.....
protected:
T* m_pData;
};
You could do it like this:
template<typename T>
class StructParamPublic;
// ^ This just "forward declares" the class for all possible template values
template<typename U>
class StructParamPublic<U*> {
...
};
// ^ This is a partial specialization of the above class template. It will deduce the type of T from the pointer type that you instantiate the template with
If you do it that way then the syntax StructParamPublic<int*> will be legal and it will deduce the type T as int in the template when you use it.
In general when you have template<typename T> class < T::dependent_type > { ... }; you should use a template specialization for it to work the way you expect, and that requires that you make the "primary" template first which is not specialized, even if that primary template doesn't actually do anything (besides make a declaration).
Note also that you don't actually need to use type traits here to enforce the pointer type requirement. In the above code if you try to use it with a non-pointer type, it will just find the primary template only and not find a real definition. If you wanted you could add a static assert in the primary template "missing * in StructParamPublic<...>" or similar.

Partially specialize with respect to values in struct given as template parameter

I have a struct which I use as template parameter to configure some classes:
template <int _DIM, class _TYPE>
struct CONFIG{
static constexpr int DIM = _DIM;
using TYPE = _TYPE;
};
I then need to partially specialize a class. I currently do this the following way:
Lines that will instantiate the template:
template <class CONFIG> instantiate(){
Calculator<CONFIG::DIM, typename CONFIG::NODE> calc;
}
The template to specialize:
template <class TYPE>
struct Calculator<2, TYPE>{
static void fct(TYPE t){
}
};
Would there be a way to directly instantiate and specialize Calculator with template parameter of type CONFIG?
Change your instantiation like so:
template <class Config> instantiate(){
Calculator<Config> calc;
}
Then specialize like this:
template <class T>
struct Calculator<CONFIG<2, T>>{
static void fct(T t){
}
};
It's generally a bad idea to overload names like you did for the template parameter CONFIG and the struct CONFIG. Although they are related to you, the compiler treats them very differently.

How to define a function for a (somewhat) partially specialized class

I'm not sure if what I'm trying to do is possible. Here's an example:
template <typename T>
class Ref
{
void Decrement();
};
template <typename T>
class Collection {};
// This will error
template <>
template <typename T>
void Ref<Collection<T>>::Decrement() {}
You can't specialize just one function inside a class template; you have to specialize the class template as a whole.
template <typename T>
class Ref
{
void Decrement();
};
template <typename T>
class Collection {};
template <typename T>
class Ref<Collection<T>> {
void Decrement() {}
};
You can specialize a function template inside a class, i.e., this:
class Ref {
template <typename U> void Decrement();
};
or a function template inside a class template...
template <typename T>
class Ref {
template <typename U> void Decrement();
};
However, even then, a partial specialization, which is what you want to do, cannot be done for a function template; function templates can only be fully specialized for individual types, and never partially specialized, whereas class templates can be either partially or fully specialized.

specialize a template class for a template function

I have two template classes like
template <class T>
class MyClass1{};
template <class T>
class MyClass2{};
and I have a template function using them as an argument. The classes are specialized with std::string:
template <template class<std::string> T> myMethod(T<std::string>& arg){}
I'd like to use myMethod(objectOfMyClass1) and myMethod(objectOfMyClass2), but the code doesn't compile. How to specialize a template class for a template function?
First, if your method does not take any arguments, you won't be able to call it as you want.
Second, MyClass1 and MyClass2 are not classes but class templates -- you cannot therefore have objectOfMyClass1 and objectOfMyClass2.
If you your function to behave specially for an argument of any type of the form SomeClassTemplate<std::string>, then what you're after is partial function template specialization, which is not allowed in C++. You will have to use a partially-specialized class instead:
template <class T>
struct MyMethodCall;
template <template <typename> class T>
struct MyMethodCall<T<std::string> > {
static void call(T<std::string> object) {
...
}
};
template <class T>
void myMethod(T & object) {
MyMethodCall<T>::call(object);
}
This is a compilable example
template <class T>
class MyClass1{};
template <class T>
class MyClass2{};
template <template <typename> class T>
void myMethod(T<std::string>& arg){}
int main()
{
MyClass1<std::string> c1;
myMethod(c1);
MyClass1<std::string> c2;
myMethod(c2);
}