LINUX.ORG.RU

template с параметром по умолчанию

 ,


0

1

Очень хотелось бы (для сокращения написанного кода) в зависимости от параметра шаблона, который в общем случае может быть задан по дефолту в описании шаблона, получать НЕМНОГО отличающиеся по реализации классы

сцуть тривиального шаблона который компилируется (правда на выполнение не проверял)

using guard = unique_lock<mutex>;

template <typename Cmd_t> class TQueue
{
private:
    const uint8_t maxQ;

    deque<Cmd_t> dqQ;

    mutex mtx;
public:

    TQueue(uint8_t lQueue)
    : maxQ(lQueue)
    { }

    ~TQueue()
    {
        if (!dqQ.empty())
            dqQ.clear();
    }

    uint8_t Put(Cmd_t cmd);
    uint8_t Get(Cmd_t & cmd);
};

template <typename Cmd_t> uint8_t TQueue<Cmd_t>::Put(const Cmd_t cmd)
{
    uint8_t rt = 0;
    {
        guard g(mtx);

        rt = dqQ.size();
        if (rt < maxQ)
        {
            dqQ.push_back(cmd);
            rt++;
        }
    }

    return rt;
}

пытаюсь что то эдакое туда засунуть

template <typename Cmd_t, sem_t * psem = NULL> class TQueue

gcc ругается

error: could not convert template argument ‘0l’ to ‘sem_t*’

а еще как бы в реализации Put проверить пришедший параметр psem на нулл и если нет, то вставить соответственно туда sem_post(), чтобы он был только в нужно месте, а не во всех классах ествественно.

премного буду благодарен за любую помощь )

★★★

template <typename Cmd_t, sem_t * psem = NULL> class TQueue

А если сменить NULL на nullptr, что получится?

а еще как бы в реализации Put проверить пришедший параметр psem на нулл и если нет

Если в наличии C++17, то можно подумать об if constexpr.

премного буду благодарен за любую помощь

Если позволите совет: не программируйте на C++, не надо. Не ваше это. В том числе и из-за самомнения и необучаемости. Проссыти за откровенность.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

точно, забыл, в плюсах же нулл это целый класс чегототам, спасибо

правда теперь в реализации получаю

template <typename Cmd_t, sem_t * psem = nullptr> uint8_t TQueue<Cmd_t, sem_t * psem>::Put(const Cmd_t cmd)
{


error: template argument 2 is invalid
 template <typename Cmd_t, sem_t * psem = nullptr> uint8_t TQueue<Cmd_t, sem_t * psem>::Put(const Cmd_t cmd)

к сожалению есть только C++14, на нем никак не получится?

) спасибо за совет, но категорически не согласен.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

правда теперь в реализации получаю

https://wandbox.org/permlink/ECazB2BgjxuBUDsX

к сожалению есть только C++14, на нем никак не получится?

Получится. Но сами вы вряд ли додумаетесь (даже если где-то и вычитаете способ). А мне лень рассказывать.

спасибо за совет, но категорически не согласен.

Да я и не надеялся. От человека с такой-то самоуверенностью :(

Жалко того, кто вам деньги за разработку платит.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от eao197

большое спасибо и на этом, действительно косяк в повторном указании типа в реализации

ну поищу поспрашиваю еще может кому не лень будет подсказать что смотреть надо.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Пользуясь случаем хочу спросить: а зачем в деструкторе TQueue вот такая вот очистка:

    ~TQueue()
    {
        if (!dqQ.empty())
            dqQ.clear();
    }

Во-первых, зачем проверять на пустоту перед вызовом clear()? Думаете, что вызов clear() для пустого дека настолько дорого, что на этом следует экономить?

Во-вторых, зачем вам вообще явный вызов clear для dpQ? Ведь у вас TQueue монопольно владеет dpQ, следовательно, когда разрушится TQueue, то автоматически разрушится и dpQ со всем своим содержимым.

Не, бывают ситуации, когда нужно гарантировать, что очередь должна быть очищена до завершения работы написанного вами деструктора TQueue (как правило, это происходит когда в dpQ помещаются заявки, которые тем или иным способом ссылаются на TQueue и в своих деструкторах эти заявки могут к TQueue обращаться). Но это, мягко говоря, экзотика. Вряд ли вы имеете с ней дело.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

это без особой причины, как напоминание что не забыть еще что то очистить вдруг надо.

а проверка - это как советуют - все проверять по цать раз )

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

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

это без особой причины, как напоминание что не забыть еще что то очистить вдруг надо.

Деструкторы в C++ были добавлены для того, чтобы не забывать. Вот и деструктор для deque сделает все в лучшем виде.

а проверка - это как советуют - все проверять по цать раз

А еще вам советуют перестать на C++ программировать, но к этому совету вы, почему-то, не прислушиваетесь.

лучше бы в SFINAE сказали что посмотреть надо

Кому лучше?

Да и не в сторону SFINAE решение лежит (по крайней мере то, которое я бы применял).

eao197 ★★★★★
()

Такое ощущение, что ты сделал using namespace std; Странно такое видеть от человека, который в соседней теме отказался от forward declaration потому что он видите ли засоряет скоуп именем типа. А тут вывалил весь std в скоуп и хоть бы хны. )))

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

) это в мейн файле, в тех что инклудятся все по заветам с указанием у каждой типа своего namespace иба там обычно их минимум 2

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

ладно, пока остановлюсь на этом - 2 пута с разными параметрами, потом может что вычитается или вместо лоровской темы унизить оппонента подскажут )

wolverin ★★★
() автор топика
Ответ на: комментарий от eao197

а еще это ub вроде же — обращение к уже разрушенному объекту — поскольку его деструктор вызывается до деструктора TQueue.


Не, бывают ситуации, когда нужно гарантировать, что очередь должна быть очищена до завершения работы написанного вами деструктора TQueue
так это гарантировано порядком разрушения сущностей.

safocl ★★
()
Ответ на: комментарий от safocl

Либо вы не так поняли, либо я пребываю в заблуждении.

Первое, если мы имеем:

#include <iostream>

class Item {
public:
    ~Item() { std::cout << "~Item()" << std::endl; }
};

class Owner {
    Item item_;
public:
    ~Owner() { std::cout << "~Owner()" << std::endl; }
};

int main()
{
    Owner owner;
    std::cout << "Good Bye!" << std::endl;
}

то деструктор Item запустится уже после того, как отработает написанный нами деструктор Owner: https://wandbox.org/permlink/D9yVSsfd1yNXG4kQ

Второе, могут быть ситуации, когда элементы в очереди прямо или косвенно ссылаются на саму очередь. И в своем деструкторе элементы обращаются к очереди. Вот примитивный синтетический пример: https://wandbox.org/permlink/9GVwATofJ1tT7ao0

Правильно ли я вас понимаю, что обращение к owner_->item_deactivated() из деструктора Item, который произошел в результате вызова items_.clear() в ~Owner – это уже UB?

так это гарантировано порядком разрушения сущностей.

Здесь я не понял вообще о чем вы.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Все дошло кажется - мне нужно шаблон от шаблона унаследовать и в наследнике вызвать родителя безумныйсмайл

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)

Не знаю что ты пытаешься сделать, но случайно не хочешь ли чтобы в зависимости от значения какой-то переменной во время выполнения (неизвестной заранее при компиляции) у тебя использовались разные инстанции шаблона?

firkax ★★★★★
()
Ответ на: комментарий от firkax

Нет, нужно просто по второму параметру тип которого заранее известен выбрать нужную реализацию для класса

Вот вроде на стековерфлоу enable_if для метода советуют, но пока не доходит как для перегруженного метода реализовать, все примеры использования нахожу только самые простецкие.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от ox55ff

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

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

самое обидное конечно, что оказалось мне такая специализация класса и не нужна, т.к. в либе к которой хотел это присобачить так же как и в другой требуется пинать планировщик с некой периодичностью и поэтому внешнее событие на семафоре не нужно для обработки очереди…

но все таки осадочек остался, как же сделать специализацию класса по параметру )

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)
Ответ на: комментарий от wolverin

enable_if

На всякий случай напомню, что SFINAE работает только в контексте подстановки шаблонного параметра. Вот так работать НЕ будет:

template<typename T>
struct Foo
{
    template<typename =
        typename std::enable_if<
            std::is_same<T, int>::value
        >::type
    >
    void print(T&& t);
};

Потому что подстановка T выполняется в struct, а SFINAE написано в print. Чтобы заработало надо делать алиас:

template<typename T>
struct Foo
{
    template<typename A = T, typename =
        typename std::enable_if<
            std::is_same<A, int>::value
        >::type
    >
    void print(A&& a);
};

Здесь подстановка A происходит в print и здесь же расположен SFINAE. Всё ок.

З.Ы. Ты там где-то обмолвился про перегрузку. Так же на всякий случай напомню, что нельзя декларировать два метода, которые отличаются только по дефолтному параметру шаблона.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

СПАСИБИЩЕ!!!

нельзя декларировать два метода, которые отличаются только по дефолтному параметру шаблона.

так вот почему нет примера, который я ищу!!! ))

…пошел читать за алиасы

wolverin ★★★
() автор топика