Constructors are special functions, but they are functions nonetheless. The language does not allow partial specialization of template functions, and thus you cannot partially specialize a constructor.
If the changes between the different versions happen in the body (rather than the initialization list), then you can move that logic to a different private function and call it using some other mechanism. Tag dispatch comes to mind:
// Make these private
template <unsigned short MODE, unsigned int N>
void AESLocker<MODE, N>::init(std::string key, std::string ivec, Int2Type<1>) {
// Specialization for MODE == 1
}
template <unsigned short MODE, unsigned int N>
template <int X>
void AESLocker<MODE, N>::init(std::string key, std::string ivec, Int2Type<X>) {
// Generic for all other modes
}
// Dispatch based on MODE
template<unsigned short MODE, unsigned int N>
AESLocker<MODE, N>::AESLocker(std::string key, std::string ivec) {
init(std::move(key), std::move(N), Int2Type<MODE>());
}
Note that I used the generic Int2Type
, forcing the use of a templated init
for the general case, but if you only want to distinguish 1
from the rest, you could use a tag type with just two options, 0
and 1
and dispatch with:
Int2Type<MODE == 1>()
In this case both overloads of init
would be non-templated. Note that there is no practical difference other than the syntax overhead, since functions are generated on demand, which means that only one init
will be generated per specialization of AESLocker
.
As Jarod42 mentions, in C++11 and above you can also use forwarding constructors to do the same:
// private constructors
template <unsigned short MODE, unsigned int N>
AESLocker<MODE, N>::AESLocker(std::string & key, std::string & ivec, Int2Type<0>)
: // initializer list
{ // constructor body
}
// public constructor
template <unsigned short MODE, unsigned int N>
AESLocker<MODE, N>::AESLocker(std::string key, std::string ivec)
: AESLocker(std::move(key), std::move(ivec), IntToType<MODE>())
{}
Where I have omitted one of the overloads. As an orthogonal change, I have modified the argument types to be referneces to strings (no need to keep moving the key
and ivec
objects around, we know the caller and we can do with the strings as we please).