как проверить std :: is_base_of <> на (* это) - PullRequest
0 голосов
/ 03 апреля 2020

Для определенной задачи мне не удалось уйти без макроса. Теперь я хотел бы добавить хоть какую-то защиту от неправильного использования.

Я бы хотел static_assert, чтобы MYMACRO () использовался

  1. в подклассе базового класса, ...
  2. ... а именно, в run() метод

Наивный подход терпит неудачу:

static_assert(std::is_base_of<Base, typeid(*this)>::value, "Use MYMACRO() only in subclass of Base.");
//                                  =============
//       SubOne would work, but not typeid(*this)
//
static_assert(__func__ == "run", "Use MYMACRO() only in run() method.");
//            ========
//       not a constexpr?
//

Воспроизвести:

#ifndef __GNUG__
#error "Needs GCC C++"
#endif

#define MYMACRO() \
{\
    do { \
    /*> > > want static_assert'ions here < < <*/\
    /*here comes stuff I coudn't put into an [inline] function,*/ \
    /*because it contains GCC Labels-as-Values and */ \
    /*conditional return;*/ \
    } while(false);\
}

class Base {
public:
    virtual int run() = 0;
};

class SubOne : Base {
public:
    int run() override {
        // ...
        MYMACRO();
        // ...
    };
};

class SubTwo : Base {
public:
    int run() override {
        // ...
        MYMACRO();
        // ...
    };
};

int main(void) 
{
    SubOne sub1;
    SubTwo sub2;
    //a little embedded app
    while (true) {
        sub1.run();
        sub2.run();
    }
}

Предвидение возможных вопросов:
Что это такое за? - http://dunkels.com/adam/dunkels06protothreads.pdf
Помечается как значения: - https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
Почему бы не "правильно" RTOS с переключением контекста? - Я ожидаю, что вышеупомянутое решение упростит модульное тестирование в собственной архитектуре, обойдя стороной необходимость собственного (POSIX) порта или QEMU / renode или целевая доска . (Не для всех, но для многих тестов)

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

Замените typeid(*this) на std::decay_t<decltype(*this)>.

И, чтобы сравнить строки во время компиляции, используйте std::string_view:

static_assert(std::string_view(__func__) == "main", "Use MYMACRO() only in run() method.");
0 голосов
/ 03 апреля 2020

typeid здесь не тот инструмент, потому что он возвращает референ в экземпляр type_info, который не является типом *this, но содержит только информацию о типе.

Вы можете использовать decltype:

#include <iostream>
#include <type_traits>


struct base {};

struct foo : base {
    foo() {
        static_assert(std::is_base_of<base,std::remove_reference<decltype(*this)>::type>::value);
    }
};

struct foo_fail {
    foo_fail() {
        static_assert(std::is_base_of<base,std::remove_reference<decltype(*this)>::type>::value);
    }
};

Выход компилятора:

prog.cc: In constructor 'foo_fail::foo_fail()':
prog.cc:15:23: error: static assertion failed
         static_assert(std::is_base_of<base,std::remove_reference<decltype(*this)>::type>::value);
                       ^~~
...