用于对抽象类进行分类的模板语法

时间:2016-08-25 12:55:14

标签: c++ templates abstract-class

在浏览某些代码时,我遇到了以下模板:

template<typename T>
class is_abstract
{
    class No { };
    class Yes { No no[3]; };

    template<class U>
    static No test(U (*)[1]); // not defined

    template<class U>
    static Yes test(...); // not defined 

public:
    enum { result = (sizeof(test<T>(0)) == sizeof(Yes)) };
};

我了解test<T>(0)将通过重载调用,该重载会为非抽象返回No is_abstract<SomeAbstractClass>::result = true )等级和其他超载否则,但为什么?

方法签名中的这个U (*)[1]语法是什么?

2 个答案:

答案 0 :(得分:4)

test<T>(0)将调用test的第一个或第二个重载。第二个过载是非常标准的(当第一个过载形成错误时它是后备)。

现在,如何使抽象类的第一个声明格式错误?以下是一些可能的解决方案:

template<class U>
static No test(U); // (1)

template<class U>
static No test(U*); // (2)

template<class U>
static No test(U (*)[1]); // (3)

(1)(2)存在问题:

  1. 您需要调用test<T>(T()),这对于任何抽象类T(不仅是声明,还有调用)都会格式不正确,因此SFINAE不起作用(因为代码格式不正确而且#34;在#34;重载解析之前)不会有后退;
  2. U*始终有效,即使是抽象类,所以这不行;
  3. 这里可能是更简单的解决方案,因为U (*)[1]不要求你在调用期间实例化T()但是声明对于抽象类型是不正确的,所以回退到test(...)的工作原理根据需要。
  4. 请注意,从C ++ 11开始,标准定义了std::is_abstract类。

    关于is_*课程的附注:

    这可能是一个旧的实现,现在有更简单的方法(从C ++ 11开始)。另请注意,使用value代替result会更好(遵循标准惯例)。遵循标准惯例的C ++ 11实现可以是 1

    template <class T>
    std::false_type is_abstract_(T (*)[1]);
    
    template <class T>
    std::true_type is_abstract_(...);
    
    template<typename T>
    struct is_abstract: decltype(is_abstract_<T>(0)) { };
    

    1 如果您需要测试某个类是否为抽象类,请使用标准std::is_abstract,但是如果您需要创建自己的is_*类,您应该按照此示例而不是您找到的示例。

答案 1 :(得分:2)

U (*)[1]是指向U的一个实例的数组的指针 由于抽象类不能实现,因此这样的数组将是格式错误的,因此忽略了重载(即SFINAE),并且调用将回退到(...)重载。