Following some discussion, here is a complete account of all cases including different access specifiers using the approach of my previous answer.
template <bool C, typename T = void>
using only_if = typename std::enable_if <C, T>::type;
template <typename A, typename B>
using eq = typename std::is_same <A, B>::type;
class SimpleClass1
{
public:
template <typename T, only_if <!eq <T, int>{} && !eq <T, float>{}, int> = 0>
SimpleClass1() { }
protected:
template <typename T, only_if <eq <T, int>{}, int> = 0>
SimpleClass1() { }
protected:
template <typename T, only_if <eq <T, float>{}, int> = 0>
SimpleClass1() { }
};
class SimpleClass2
{
public:
template <typename T, only_if <!eq <T, int>{} && !eq <T, float>{}, int> = 0>
SimpleClass2(T) { }
protected:
template <typename T, only_if <eq <T, int>{}, int> = 0>
SimpleClass2(T) { }
private:
template <typename T, only_if <eq <T, float>{}, int> = 0>
SimpleClass2(T) { }
};
template <typename T>
class ClassTemplate1
{
public:
template <typename U, only_if <!eq <U, int>{} && !eq <U, float>{}, int> = 0>
void Method() { }
protected:
template <typename U, only_if <eq <U, int>{}, int> = 0>
void Method() { }
protected:
template <typename U, only_if <eq <U, float>{}, int> = 0>
void Method() { }
};
template <typename T>
class ClassTemplate2
{
public:
template <typename U, only_if <!eq <U, int>{} && !eq <U, float>{}, int> = 0>
void Method(U) { }
protected:
template <typename U, only_if <eq <U, int>{}, int> = 0>
void Method(U) { }
protected:
template <typename U, only_if <eq <U, float>{}, int> = 0>
void Method(U) { }
};
I don't know where all this would be useful :-) Anyhow:
I have been careful to make all constructor/method overloads mutually exclusive to avoid ambguities and problems with different access specifiers, which can be tricky. This makes it more difficult to generalize to more types. A template alias would help for the generic/default case (which is the complement of all others).
However, this is not exactly equivalent to what you described in the question. These methods enforce strict type equality, so do not allow implicit conversions. You could try
std::is_convertible
instead but then you're opening the door to ambiguities.The entire code compiles as such but I didn't try to actually use the classes, so I don't know what might happen.
I really don't know how one can use
SimpleClass1
: How can we possibly explicitly specify a template argument for a default constructor (since it cannot be deduced)?Looking at the code again, I think that
ClassTemplate
is not much different (or at all) fromSimpleClass
.ClassTemplate1
cannot have a default template argument, because that would be ambiguous.