2013-07-18 3 views
16

Предположим, что мы имеемВ чем причина std :: chrono :: отсутствие длительности немедленного манипулирования счетчиком?

#include <chrono> 
#include <iostream> 
#include <ctime> 

namespace Ratios { typedef std::ratio<60*60*24,1> Days; } 

typedef std::chrono::system_clock Clock; 
typedef Clock::time_point TimePoint; 

И наш main выглядит

int main(int argc, char *argv[]) 
{ 
    // argc check left out for brevity 
    const Clock::rep d = static_cast<Clock::rep>(std::atoi(argv[1])); 
    // Right now 
    TimePoint now = Clock::now(); 
    // Start with zero days 
    auto days = std::chrono::duration<Clock::rep, Ratios::Days>::zero(); 

    // Now we'd like to add d to the days 
    days += d; // Error! 
    days.count() = d; // Error! 
    days = days + d; // Error! 
    days += std::chrono::duration<Clock::rep, Ratios::Days>(d); // Okay 
    days = days + std::chrono::duration<Clock::rep, Ratios::Days>(d); // Okay 

    days *= d; // Why is this okay? 
    days %= d; // And this too? 

    TimePoint later = now + days; 

    return 0; 
} 

Что является причиной, запрещающее пользователю манипулировать duration напрямую?

+0

Так много хороших ответов ... Я могу принять только один :) – rwols

ответ

23

Это делается для того, чтобы заставить вас придерживаться строго типизированных значений, а не произвольных значений.

Бьерн Страуструп есть примеры, касающиеся этого поведения в "Язык программирования C++" (4-е изд, 35.2.1, стр 1011..):


"Период представляет собой системный блок, поэтому нет = или += принимает простую величину Учитывая, что будет, как возможности добавления 5 неизвестной единицы СИ на длину в метрах Рассмотрим:..

duration<long long, milli> d1{7}; // 7 milliseconds 
d1 += 5; // error 
[...] 

Что означали бы здесь? 5 секунд? 5 миллисекунд? [...] Если вы знаете, что вы имеете в виду, будьте откровенны в этом. Например:

d1 += duration<long long, milli>{5}; //OK: milliseconds" 

1

Я бы предположил, что это сделано, чтобы заставить вас рассмотреть, какие единицы продолжительности вы хотите добавить/вычесть. Это также не позволяет вам делать какие-либо предположения о том, в каких единицах используются часы.

13

Смысл заключается в том, чтобы сохранить целостность блока времени, который представляет duration.

Вы можете думать о rep как о безразмерном. Но у duration есть единица времени. Можно добавить и вычесть секунды в/из секунд. Но нельзя добавлять секунды и единицы меньше, не делая выражение неоднозначным и нарушая алгебру единиц.

При этом один может умножить и разделить единицу времени на скалярное (без единицы) количество, и результат по-прежнему остается единицей времени. Эта библиотека представляет только единицы времени до первой мощности или нулевой мощности. Единица времени, поднятая до нулевой мощности, является скаляром и представлена ​​rep. Единицы времени также могут иметь мощность 2 или более и отрицательные мощности. Однако эта библиотека не представляет такие единицы.

При добавлении двух величин единицы измерения должны быть одинаковыми.

При умножении или разделении двух величин формируется новый блок (например, км/ч). Когда количества одних и тех же единиц умножаются, их экспоненты добавляются (например, sec * sec == sec^2). Когда количества одних и тех же единиц делятся, их показатели вычитаются (например, sec/sec == sec^0 == скаляр).

std::chrono::duration библиотека является последовательным подмножеством физической библиотеки величин, которая обрабатывает только единицы времени и только те единицы времени с показателями, равными 0 и 1.

+0

Конечно, прекрасная обработка блоков ломается, когда дело доходит до обработки нуля, так как нуль не зависит от единиц. Конечно, это ограничение исходит от нулевых литералов, не имеющих собственного типа на C++ - трудно принять нуль без принятия произвольных скаляров. (Конечно, было бы неплохо иметь возможность сказать 'if (d <0)' где 'd' некоторая продолжительность.) –

8
days += d; // Error! 

Это происходит потому, что переменная days является в единицах 86 400 секунд, а переменная d без единиц. Результат добавления количества единицы в единичный скаляр не определяется при стандартном анализе размеров.

days *= d; // Why is this okay? 
days %= d; // And this too? 

Поскольку умножение и деление величин на безразмерные скаляры не имеет смысла. Умножение на 2 секунды на 2 результата за 4 секунды.

Рассмотрите возможность умножения на 2 секунды на 3 секунды; результатом является величина 6 с единицей «квадрат секунд». Конечно, chrono::duration не является полной библиотекой единиц, поэтому у вас не может быть единиц, таких как квадрат времени, но библиотеки, такие как boost.units, будут поддерживать это.