Упростить написание кода макросом

260
28 марта 2018, 05:59

Имеется множество примерно таких методов:

void libvlc::Interop::LibVLCHelper::libvlc_media_player_set_media(libvlc_media_player_t * p_mp, libvlc_media_t * p_md)
{
    if (!m_vlc_media_player_set_media)
    {
        m_vlc_media_player_set_media = m_libvlc_->Resolve<vlc_media_player_set_media>(__func__);
    }
    (*m_vlc_media_player_set_media)(p_mp, p_md);
}

Хочу сделать примерно такой макрос:

#define MF(t, x, name) if (!(x)) { (x) = m_libvlc_->Resolve<t>(name); }

И определение на валидность упрощается соответственно до такого вида:

libvlc_media_player_t * libvlc::Interop::LibVLCHelper::libvlc_media_player_new(libvlc_instance_t * p_instance)
{
    MF(vlc_media_player_new, m_vlc_media_player_new, __func__);
    return (*m_vlc_media_player_new)(p_instance);
}

Да, он работает, но можно ли улучшить макрос до примерно такого вызова?

libvlc_media_player_t * libvlc::Interop::LibVLCHelper::libvlc_media_player_new(libvlc_instance_t * p_instance)
{
    MF(vlc_media_player_new, __func__);
    return (*m_vlc_media_player_new)(p_instance);
}

Для понятия: Макрос принимает тип, 1м параметром, подставляет m_(тут тип), и вид примерно такой:

#define MF(t, name) if (!(m_#t)) { (m_#t) = m_libvlc_->Resolve<t>(name); }

Не очень хорошо дружу с макросами, и не могу понять как такое реализовать.

Примечание: Имя поля всегда отличается от типа только добавочным m_

Answer 1

Ваш код

#define MF(t, name) if (!(m_#t)) { (m_#t) = m_libvlc_->Resolve<t>(name); }

почти правильный. Для token pasting («склеивания» токенов) нужно использовать удвоенный символ диеза.

#define MF(t, name) if (!(m_##t)) { (m_##t) = m_libvlc_->Resolve<t>(name); }

(Практически одновременно тот же совет в комментарии дал @VTT.)

Answer 2

Долой макросы! Даёшь шаблоны и вывод типов!

Предположу, что можно упростить код до следующего.

class /* имя класса, отвечающего переменной m_libvlc_ */ {
    ...
    template <class T>
    T& SafeGet(T*& member, const char* func) {
        if (!member) {
            member = Resolve<T>(func);
        }
        return *member;
    }
}

Использование:

void libvlc::Interop::LibVLCHelper::libvlc_media_player_set_media(libvlc_media_player_t * p_mp, libvlc_media_t * p_md)
{
    m_libvlc_->SafeGet(m_vlc_media_player_set_media, __func__)(p_mp, p_md);
}

Ну и если всё-таки хочется макрос..

#define SAFE_GET(member) m_libvlc_->SafeGet(member, __func__)

и

void libvlc::Interop::LibVLCHelper::libvlc_media_player_set_media(libvlc_media_player_t * p_mp, libvlc_media_t * p_md)
{
    SAFE_GET(m_vlc_media_player_set_media)(p_mp, p_md);
}

P.S. Можно добавить в этот вызов и аргументы через class ...Args в шаблоне, но такой вариант показался приятнее.

READ ALSO
Зашифровать файл и разшифровать

Зашифровать файл и разшифровать

При расшифровке в конце файла появляются лишние символыС чем это связано?

287
Запись и удаления из vector

Запись и удаления из vector

Как правильно удалять последний item из вот таких вот структур, и записывать следующий в самое начало, чтобы последующие iD повышались на 1

271
Ввод данных с клавиатуры в OpenGL (C++)

Ввод данных с клавиатуры в OpenGL (C++)

Как ввести данные во время выполнения программы в OpenGL?

242
Хочу написать приложение

Хочу написать приложение

Я новичок, изучаю С++ и для практики хочу написать (может списать) приложение похожее на ankiappAnkiapp - это карточки для запоминания, например, английских...

242