Использование std::is_base_of с decltype в иерархии классов

#c #c 11

#c #c 11

Вопрос:

Для краткости это упрощенная иерархия:

 class IBase
{
public:
    virtual ~IBase() = 0 { };
};  // eo IBase


class IDerived : public virtual IBase
{
public:
    virtual ~IDerived() = 0 { };
};  // eo IDerived

class Base : public virtual IBase
{
public:
    Base() { };
    virtual ~Base() { };
};  // eo Base


class Derived : public IDerived
              , public Base
{
};  // eo Derived
 

И функция для определения, реализует ли конкретный указатель на класс переданный «интерфейс»:

 template<typename T>
bool same(IBase* base)
{
    if(std::is_base_of<T, decltype(*base)>::value)
        return true;
    return false;
};
 

И пример:

 IDerived* i(new Derived());
bool isSame = same<IDerived>(i);
 

Я знаю, что могу неправильно использовать decltype здесь. Кажется, что бы я ни пытался, std::is_base_of<B,D>::value это всегда false . Я хочу, чтобы эта функция выполняла, отвечала на вопрос:

Является ли объект, на который указывает, производным от type ( T ), переданного в качестве параметра шаблона?

Ответ №1:

decltype , например sizeof , это конструкция времени компиляции. Это означает, decltype(*base) что даст статический тип выражения *base , который есть IBase . Так что то, чего вы намереваетесь достичь, не может быть сделано таким образом.

Я бы предложил такое решение:

 template<typename T>
bool same(IBase* base)
{
     return dynamic_cast<T*>(base) != nullptr;
};
 

Комментарии:

1. Спасибо за это. Я надеялся избежать использования dynamic_cast. Но, похоже, на данный момент это правильный путь.

Ответ №2:

 template<typename T>
bool same(IBase* base)
{
    if(std::is_base_of<T, decltype(*base)>::value)
 

Это не может работать. decltype(*base) было бы IBase (всегда), поэтому оно никогда не будет отражать тип среды выполнения base .

Вероятно, лучшее, что вы можете сделать, это dynamic_cast<T*>(base)!=0 .