I am trying to wrap my head around template specialization, and I am a bit confused (perhaps not understanding what typename actually is, or what the compiler expects)
Example 1 (Compiles):
template <typename A, typename... Args>
class Example
{
public:
Example(){}
virtual ~Example(){}
};
template <typename A, typename... Args>
class Example<A, int, Args...>{
Example(){}
virtual ~Example(){}
};
Example 2 (Compiles):
template <typename A, int, typename... Args>
class Example
{
public:
Example(){}
virtual ~Example(){}
};
template <typename A, typename... Args>
class Example<A, 2, Args...>{
Example(){}
virtual ~Example(){}
};
Example 3 (Fails):
template <typename A, typename... Args>
class Example
{
public:
Example(){}
virtual ~Example(){}
};
template <typename A, typename... Args>
class Example<A, 2, Args...>{
Example(){}
virtual ~Example(){}
};
The error is:
error: type/value mismatch at argument 2 in template parameter list for ‘template class Example
Questions:
First, I am new to generic programming, and I hope I am asking the right questions. The compiler spec terminology is still a bit foreign to me.
Thank you
EDIT/Solution:
After I understood what is going on (from Yakk's explanation), here is how my final solution looks like. I read somewhere by one of the C++ guru's that "You can solve any problem by adding another layer of abstraction". Now I know what that means :D
enum ETypes
{
UNKNOWN = 0,
INT = 1,
FLOAT = 2,
STRING = 3,
FUNC = 4,
};
// This is to use the ETypes as a type.
// Note that T is not a type, hence use it as RHS
template<ETypes T>
class ETypeName
{
public:
ETypes type = T;
};
// The example
template <typename A, typename... Args>
class Example
{
private:
Example(); // Hide the constructor as private
// to generate compilation error
virtual ~Example(){}
};
// LOOK! We can use the Enum to specialize the class.
template <>
class Example<ETypeName<ETypes::INT>>{
public:
ETypes mType;
Example():mType(ETypes::INT){}
virtual ~Example(){}
};
And in main():
Example<ETypeName<ETypes::INT>> x;
// This can't happen. Private constructor. Not specialized yet
// Example<ETypeName<ETypes::FLOAT>> x1;
A primary specialization looks like this:
template <typename A, typename... Args>
class Example
When you type Example<stuff goes here>
, it is always matched against the primary specialization's <typename A, typename... Args>
argument list.
This is a completely different beast:
template <typename A, typename... Args>
class Example<A, int, Args...>
This is a secondary specialization. Here,
template <typename A, typename... Args>
is not the argument list, but rather the deduction list.
The argument list is:
class Example<A, int, Args...>
here. What is between the <>
is only used to pattern match against arguments passed to the primary specialization.
Types and non-type template parameters are different things. The primary specialization details what arguments are type, and what arguments are non-type.
Once they have matched against the primary, each of the secondary specializations are pattern matched against the arguments. Each viable candidate is examined, and a reasonably complex system is used to determine which is "more specialized", the rules of which I won't go into here.