I have the following classes:
template <class... T>
class thing {};
template <class T>
class container {
public:
container() {
std::cout << "normal constructor" << std::endl;
}
};
I can write a full specialization for the constructor of container<int>
in this way:
template <>
container<int>::container() {
std::cout << "int constructor" << std::endl;
}
I would like to be able to define a similar constructor for container<thing<T>>
. I think what I'm attempting to write is a partial specialization of a template function (which is illegal.) Here is what I'm attempting:
template <class T>
container<thing<T>>::container() {
}
This does not compile.
I am not entirely sure what the correct way to go about solving this problem is and the lines between what an overload and a specialization are for a template class function are getting blurred. Can this be trivially solved or will it require type_traits (std::enable_if
)? How can I solve this?
You can't partial specialize the constructor but you don't have necessarily to partial specialize the full class.
Can this be trivially solved or will it require type_traits/enable_if? How can I solve this?
Delegating constructors and tag dispatching can work around the limitation.
It follows a minimal, working example:
#include<iostream>
template <class... T>
class thing {};
template <class T>
class container {
template<typename>
struct tag {};
template<typename U>
container(int, tag<thing<U>>) {
std::cout << "thing<U>" << std::endl;
}
container(char, tag<T>) {
std::cout << "normal constructor" << std::endl;
}
public:
container(): container(0, tag<T>{}) {}
};
int main() {
container<int> c1;
container<thing<int>> c2{};
}
See it on wandbox.
Note that you can easily extend it if you want to have more than two delegating constructors from which to pick the right one up.
As an example:
#include<iostream>
template <class... T>
class thing {};
template<typename> struct tag {};
template<int N> struct prio: prio<N-1> {};
template<> struct prio<0> {};
template <class T>
class container {
template<typename U>
container(prio<2>, tag<thing<U>>) {
std::cout << "thing<U>" << std::endl;
}
container(prio<1>, tag<double>) {
std::cout << "double" << std::endl;
}
container(prio<0>, tag<T>) {
std::cout << "normal constructor" << std::endl;
}
public:
container(): container(prio<2>{}, tag<T>{}) {}
};
int main() {
container<int> c1;
container<double> c2;
container<thing<int>> c3{};
}
See it on wandbox.