Compiler cannot find specialized class template - c++

I want to use partial template specialization but it seems I am missing something.
Here is what I've tried:
template<class T1, class T2>
class AClass {};
template<class T>
class AClass<T, T> {}; // specialized class.
AClass<int,float> aClassIntFloat; // works just fine
AClass<int, int> aClassIntInt; // works just fine
AClass<int> specializedIntClass; //"error: wrong number of template arguments (1, should be 2)"
What am I missing?

First of all, you have already successfully defined a partial specialistation:
AClass<int, int> will instantiate class AClass<T, T> with T=int
AClass<int,float> will instantiate class AClass<T1, T2> with T1=int and T2=float
You can easily check this by adding a public test method and invoking it for aClassIntFloat and aClassIntInt (online demo). You'll find out that the partial specialization defined for two identical types will be used.
You can also make another partial specialization, for example:
template<class T2>
class AClass<double, T2> { public: void test(){cout<<"ADT2"<<endl;}};
AClass<double, int> aClassDoubleInt; // works also fine
A partial specialization lets you fix some parameters but not all. But in the end, your template requires two parameters, and you'll have to provide two parameters. The only question is which specialization if any gets instantiated (online demo).

Related

Is it possible to overload template classes in c++?

I'm currently creating some utilities for my projects, and I came up with the idea to replicate the C# Action class in C++. As you can see in the C# documentation, the Action class can have different "overloads" with templates. It has Action, Action<T1>, Action<T1, T2\>, etc.
Is it possible to overload classes like this in C++? Or, is there any workaround?
This is an example of "pseudocode", C++ throws a syntax error with this:
class Action
{
// Code
};
template<class T1>
class Action
{
// Code
};
template<class T1, class T2>
class Action
{
// Code
};
// etc...
So that you can call different kinds of classes depending if you input a template or not, like this:
int main()
{
Action a1;
Action<int> a2;
Action<int, float> a3;
// etc...
return 0;
}
I tried various things, such as:
template<T1, T2>
class Action {};
template<T1, T2>
class Action<T1.> {};
template<T1, T2>
class Action<T1, T2> {};
But this does not work.
No, classes can't be overloaded. Action in the scope can be either a single non-templated class or a single class template with a given template head (not different ones).
But, a given class template can be specialized for certain template arguments and there are variadic templates since C++11 which accept an arbitrary number of template arguments:
template<typename... Ts>
class Action { /* generic case */ };
This allows for a2 and a3 and via explicit or partial specialization they can be specialized for e.g. one or two template arguments:
template<typename T1>
class Action<T1> { /* one template argument */ };
template<typename T1, typename T2>
class Action<T1, T2> { /* two template arguments */ };
a1 can also work since C++17 via class template argument deduction (CTAD) depending on which constructors the primary class template has and/or what deduction guides are declared.
I don't have enough knowledge of C# or context to know whether this is a useful approach to take for your underlying problem though.
Also, as a side note: class and typename when introducing template parameters in the template head are synonymous. Choose class if you prefer that. There is no difference.

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.

Can I use std::vector as a template parameter or does it need to be std::vector<T>?

I know this is a simple question but I just could not find the answer.
I am trying to do something like this but instead of with std::vector ultimately I want it to be std::shared_ptr or std::weak_ptr:
template <int dim, class ChunkClass, class PtrClass>
class BaseChunkWindow : public IChunkWindow<BaseChunkWindow<dim, ChunkClass, PtrClass>, IChunk<ChunkClass>> {
public:
...
private:
PtrClass< IChunk<ChunkClass> > ptr; <-- compiler doesn't like this line, however IChunk<ChunkClass>* works
};
It depends on what you are passing it to, if the template you're trying to instantiate takes as a parameter a class template accepting 2 (or in c++11 a variadic number of) types then you can pass std::vector to that. In most cases however, templates require types as parameters and you cannot pass the class template std::vector.
template <class T>
struct gimme_a_type{};
template <template <class,class> class T>
struct gimme_a_template{};
gimme_a_type<std::vector> //<-- does not compile, expected a type, got a template
gimme_a_type<std::vector<int> > //<-- compiles, expected a type, got a type
gimme_a_template<std::vector> //<-- compiles, expected a template, got a template that has the correct signature
gimme_a_template<std::vector<int> > //<-- does not compile, expected a template, got a type
In response to your edit, there are difficulties to using class templates as template parameters. Matching the number of parameters exactly is actually difficult to do when you have default arguments in the class template you're trying to pass (std::vector in our case).
Notice that the example above required a class template that takes 2 types, not just one. This is because std::vector takes two parameters, the second is just defaulted to std::allocator<T> for us.
The following example demonstrates the issue:
template <template <class, class> class Tem>
struct A
{
Tem<int> v; //<-- fails to compile on gcc, Tem takes two parameters
Tem<int, std::allocator<int> >; //<-- compiles, but requires a priori knowledge of Tem
};
template <template <class...> class Tem>
struct A2
{
Tem<int> v; //<-- This C++11 example will work, but still isn't perfect.
};
The C++11 example is better, but if someone passed a class that has as a signature template <class, bool = false> class A3 it fails again because A2 requires a class template that takes types and not a mix of types and non-types (false being the non-type template parameter in this example). So even though A3<int> would be a valid instantiation you couldn't pass that class to A2.
The solution there is to always use types in template parameter lists and use the std::integral_constant wrapper template to pass integral constants around.
There are a couple ways of doing it.
The limited way would be to use a template template parameter with just a limited number of parameters being passed, e.g. 3.
template<template<class,class,class> class Cont, class T, class V, class U>
void f(Cont<T,V,U>&& cont) {
//...
}
However that's pretty limiting and can be hard to manage if you decide to change it in the future.
So you can do it like so with the new Variadic Templates in C++11:
template<template<class...> class Cont, typename F, typename... Rest>
void f(Cont<F, Rest...>&& cont) {
//...
}
This would work on other containers or things and is probably much easier to manage.

C++ - Overload templated class method with a partial specilization of that method

There are a few questions already similar to this already on stack overflow, but nothing that seemd to directly answer the question I have. I do apologise if I am reposting.
I'd like to overload a few methods of a templated class (with 2 template parameters) with a partial template specialisation of those methods. I haven't been able to figure out the correct syntax, and am starting to think that it's not possible. I thought I'd post here to see if I can get confirmation.
Example code to follow:
template <typename T, typename U>
class Test
{
public:
void Set( T t, U u );
T m_T;
U m_U;
};
// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
m_T=t;
m_U=u;
}
// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
m_T=t;
m_U=u+0.5f;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test<int, int> testOne;
int a = 1;
testOne.Set( a, a );
Test<int, float> testTwo;
float f = 1.f;
testTwo.Set( a, f );
}
I know that I could write a partial specialisation of the entire class, but that kinda sucks. Is something like this possible?
(I'm using VS2008)
Edit: Here is the compile error
error C2244: 'Test::Set' : unable to match function definition to an existing declaration
Thanks :)
You cannot partially specialize a member function without defining partial specialization of the class template itself. Note that partial specialization of a template is STILL a template, hence when the compiler sees Test<T, float>, it expects a partial specialization of the class template.
--
$14.5.4.3/1 from the C++ Standard (2003) says,
The template parameter list of a
member of a class template partial
specialization shall match the
template parameter list of the class
template partial specialization. The
template argument list of a member of
a class template partial
specialization shall match the
template argument list of the class
template partial specialization. A
class template specialization is a
distinct template. The members of the
class template partial specialization
are unrelated to the members of the
primary template. Class template
partial specialization members that
are used in a way that requires a
definition shall be defined; the
definitions of members of the primary
template are never used as definitions
for members of a class template
partial specialization. An explicit
specialization of a member of a class
template partial specialization is
declared in the same way as an
explicit specialization of the primary
template.
Then the Standard itself gives this example,
// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }
// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
I hope the quotation from the Standard along with the example answers your question well.
The particular problem you're sketching is easy:
template< class T >
inline T foo( T const& v ) { return v; }
template<>
float foo( float const& v ) { return v+0.5; }
Then call foo from your Test::Set implementation.
If you want the full generality, then similarly use a helper class with static helper member functions, and partially specialize that helper class.
Cheers & hth.,
There's also another solution to the partial specialization problem, if you don't want to introduce additional functions, methods or classes to your code.
#include <type_traits>
template <typename T1, typename T2>
class C
{
void f(T1 t1);
}
template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
if (std::is_same<T2, float>::value)
// Do sth
else
// Do sth
}

Template specialization with struct and bool

I have a template class in which I am specializing a couple of methods. For some reason, when I added a specialization for a struct, it seems to be conflicting with the specialization for bool. I am getting a type conversion error because it is trying to set the struct = bool (resolving to the wrong specialization). Here is some code
.h:
typedef struct foo {
...
}
template <class T> class bar {
template <class T> void method1() {...}
template <> void method1<bool>() {...}
template <> void method1<foo>() {...}
}
.cpp
template class bar<bool>;
template class bar<foo>;
I am getting the error inside method1<bool> because it is setting T=foo instead of resolving it to method1<foo>.
Any ideas?
The first part of your code is already incorrect. C++ does not support explicit specialization of "nested" (member) templates without explicit specialization of the enclosing template.
In the context of your code, it is illegal to explicitly specialize template method method1 without explicitly specializing the entire class template bar.
If your member template function member1 depended on some parameters, you could use overloading instead of template specialization as a workaround. But since it doesn't, you have to redesign you templates somehow. What you do above is, once again, illegal in C++.
The errors you get further down can easily be (and most probably are) induced by that original problem.
P.S. The description of the problem you posted implies that your code compiles. What you posted should not compile for the reasons described above. This suggests that you are posting fake code. Post real code.
(EDITED)
You may try the following, which delegates the method implementation to a templated helper class.
.h:
typedef struct Foo {
...
}
template<class T_Bar, class T2> struct BarMethod1;
template <class T> class Bar
{
template<class T2> void method1(...)
{
BarMethod1<Bar, T2>(...)(...);
}
}
template <class T_Bar, class T2> class BarMethod1
{void operator()(...){...}};
template <class T_Bar> class BarMethod1<T_Bar, bool>
{void operator()(...){...}};
template <class T_Bar> BarMethod1<T_Bar, Foo>
{void operator()(...){...}};
.cpp
template class Bar<bool>;
template class BarMethod1<Bar<bool>, bool>;
template class BarMethod1<Bar<bool>, Foo>;
template class Bar<Foo>;
template class BarMethod1<Bar<Foo>, bool>;
template class BarMethod1<Bar<Foo>, Foo>;