The program below does not compile if I uncomment the line containing foo<double>()
, because B<double>
depends on A<double>
, which is an incomplete type.
#include <iostream>
using namespace std;
template <class T> struct A; // forward declaration (incomplete)
template <> struct A<int> {}; // specialized for int
template <class T> struct B : A<T> { int foo() {return 0;} }; // derived class, general definition inherits from A
template <> struct B<bool> { int foo() {return 1;} }; // derived class, does not inherit from A
template <class T> int foo() { B<T> b; return b.foo(); } // to be called if B<T> is valid
int main()
{
cout << foo<int>() << "\n"; // print 0
cout << foo<bool>() << "\n"; // print 1
// cout << foo<double>() << "\n"; // this line would generate a compile error
}
I would like a way to overload the function foo
so that if B<T>
is not a valid type, then an alternative version of the function foo
is called.
I.e. I would like to have a way to define the overload
template <class T> int foo() { return -1; } // to be called if B<T> is not valid
I can also wrap the function foo
inside a struct, if that helps. Is there a way to do that in C++03?
Remembering your analogue question and the answer from Quentin, I see that the problem is that B<T>
can be (apparently) complete when A<T>
is incomplete.
The only way I see (sorry: only C++11 at the moment) is impose that the general B<T>
is defined only if A<T>
is defined (trasforming it in a partial specialization); in the following way
template <typename T, bool = is_complete<A<T>>::value>
struct B;
template <typename T>
struct B<T, true> : A<T>
{ int foo() {return 0;} };
template <>
struct B<bool>
{ int foo() {return 1;} };
If you can modify B
in this way, the solution is simple (using again the is_complete
developed by Quentin).
The following is a working example
#include <iostream>
#include <type_traits>
template <typename T, std::size_t = sizeof(T)>
std::true_type is_complete_impl(T *);
std::false_type is_complete_impl(...);
template <typename T>
using is_complete = decltype(is_complete_impl(std::declval<T*>()));
template <typename>
struct A;
template <>
struct A<int>
{ };
template <typename T, bool = is_complete<A<T>>::value>
struct B;
template <typename T>
struct B<T, true> : A<T>
{ int foo() {return 0;} };
template <>
struct B<bool>
{ int foo() {return 1;} };
template <typename T>
typename std::enable_if<true == is_complete<B<T>>::value, int>::type foo()
{ B<T> b; return b.foo(); }
template <typename T>
typename std::enable_if<false == is_complete<B<T>>::value, int>::type foo()
{ return 2; }
int main()
{
std::cout << foo<int>() << "\n"; // print 0
std::cout << foo<bool>() << "\n"; // print 1
std::cout << foo<double>() << "\n"; // print 2
}