Различать длительности std :: chrono с одинаковым типом и соотношением? - PullRequest
0 голосов
/ 01 декабря 2018

Я ищу строго типизированное решение для std::chrono продолжительности.У меня есть типы продолжительности, которые зависят только от времени выполнения.Я использую фабрично-подобный класс для преобразования длительностей с использованием значения времени выполнения.Например:

#include <chrono>
#include <cstdio>

using dseconds = std::chrono::duration<double>;
using blee = std::chrono::duration<double, std::ratio<1,1>>;
using tick = std::chrono::duration<size_t, std::ratio<1,64>>;

struct converter {
    tick to_tick(dseconds s) const {
        return std::chrono::duration_cast<tick>(s / runtime_ratio);
    }

    tick to_tick(blee b) const {
        return std::chrono::duration_cast<tick>(b);
    }

private:
    double runtime_ratio = 0.5;
};

int main(int, char**) {
    converter c;
    printf("%zu", c.to_tick(dseconds{1}).count());
    printf("%zu", c.to_tick(blee{1}).count());
}

Пример доступен на проводнике компилятора .

Обратите внимание, что при преобразовании в секундах применяется соотношение, в отличие от преобразования из blee.Это не компилируется, так как dseconds и blee действительно одного типа.

<source>:13:10: error: 'tick converter::to_tick(blee) const' cannot be overloaded with 'tick converter::to_tick(dseconds) const'
     tick to_tick(blee b) const {
          ^~~~~~~

<source>:9:10: note: previous declaration 'tick converter::to_tick(dseconds) const'
     tick to_tick(dseconds s) const {
          ^~~~~~~

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

Есть ли способ строго ввести псевдоним продолжительности 2 стого же типа и соотношения?

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Я предложу еще раз: использовать наследование .

Сейчас ваша проблема заключается в использовании псевдонимов типов через using.Это не создает новые типы, только новые имена для старых типов.Вы пытаетесь дважды перегрузить одним и тем же типом, что бессмысленно и невозможно, поскольку перегрузка не заботится о новых именах.

Но наследование создает типы .Это его работа;это его цель.

С этим вы можете легко сделать то, что иногда называют «сильным определением типа» - свежий, отличный тип, который в остальном ведет себя почти так же, как то, что вы получаете.

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

Итак, ладно, вам нужно потратить несколько строк на настройку типов.И, ладно, вам нужно немного расширить вызов duration_cast.

Но, честно говоря, это небольшая цена, которую нужно заплатить, чтобы получить решение, не основанное на хакерстве!

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

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

0 голосов
/ 02 декабря 2018

Хорошо, я понял, что-то вроде взлома.Если вы используете std::ratio<2,2>, что в любом случае эквивалентно std::ratio<1,1>, компилятор прекращает жаловаться и обрабатывает dseconds и blee как разные типы.

Я оставлю вопрос открытым, если у кого-то естьлучшее решение.

#include <chrono>
#include <cstdio>

using dseconds = std::chrono::duration<double>;
using blee = std::chrono::duration<double, std::ratio<2,2>>;
using tick = std::chrono::duration<size_t, std::ratio<1,64>>;

struct converter {
    tick to_tick(dseconds s) const {
        return std::chrono::duration_cast<tick>(s / runtime_ratio);
    }

    tick to_tick(blee b) const {
        return std::chrono::duration_cast<tick>(b);
    }

private:
    double runtime_ratio = 0.5;
};

int main(int, char**) {
    converter c;
    printf("%zu", c.to_tick(dseconds{1}).count());
    printf("%zu", c.to_tick(blee{1}).count());
}

проводник компилятора

...