A C++11 solution could be based on SFINAE: enabling the first or the second constructor if U
is a S
based type or not.
To make this, can be useful develop a type traits to detect if a type is (or isn't) S
based; by example
template <typename>
struct isS : public std::false_type
{ };
template <typename T>
struct isS<S<T>> : public std::true_type
{ };
With isS
, you can write your constructors (in the body of the A
class) as follows
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
If you need the template argument of S
, you can define the specialization of isS
as follows
template <typename T>
struct isS<S<T>> : public std::true_type
{ using type = T; };
and use it as typename isS<V>::type
.
A full working example
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
struct S
{
S (T const &, bool, bool)
{ std::cout << "S constructor" << std::endl; }
};
template <typename>
struct isS : public std::false_type
{ };
template <typename T>
struct isS<S<T>> : public std::true_type
{ };
template <typename T, typename U>
struct A : public U
{
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
};
int main ()
{
long l { 0L };
// print "generic A constructor"
A<long, std::vector<int>> alv(l, true);
// print "S constructor>" and "S specific A constructor"
A<long, S<int>> als(l, true);
}