How to write template overload functions with fallback triggered if template arguments do not allow instantiation of a certain class

柔情痞子 提交于 2019-12-12 17:09:35

问题


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?


回答1:


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
 }


来源:https://stackoverflow.com/questions/44237528/how-to-write-template-overload-functions-with-fallback-triggered-if-template-arg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!