如何编写模板重载函数,并在模板参数不允许实例化某个类时触发回退

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

本文关键字:回退 实例化 参数 函数 重载 何编写 不允许      更新时间:2023-10-16

如果我取消注释包含foo<double>()的行,下面的程序将无法编译,因为B<double>依赖于A<double>,这是一个不完整的类型。

#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
}

我想要一种重载函数foo的方法,以便如果B<T>不是有效类型,则调用函数foo的替代版本。 即我想有一种方法来定义重载

template <class T> int foo() { return -1; }  // to be called if B<T> is not valid

如果有帮助,我还可以将函数foo包装在结构中。有没有办法在 C++03 做到这一点?

记住你的模拟问题和昆汀的答案,我发现问题是当A<T>不完整时,B<T>可以(显然)完成。

我看到的唯一方法(对不起:目前只有C++11)是强加一般B<T>只有在定义A<T>时才定义(在部分专业化中对其进行传输);

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;} };

如果能用这种方式修改B,解决方案很简单(再次使用昆汀开发的is_complete)。

下面是一个工作示例

#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
}