2015-11-15 15 views
6

W opracowaniu standardów P0092R1, Howard Hinnant napisał:Jak ten kod może być constexpr? (Std :: Chrono)

template <class To, class Rep, class Period, 
      class = enable_if_t<detail::is_duration<To>{}>> 
constexpr 
To floor(const duration<Rep, Period>& d) 
{ 
    To t = duration_cast<To>(d); 
    if (t > d) 
     --t; 
    return t; 
} 

W jaki sposób ta praca kod? Problem polega na tym, że operator-- na std::chrono::duration nie jest operacją constexpr. Jest ona definiowana jako:

duration& operator--(); 

I jeszcze ten kod kompiluje i daje właściwą odpowiedź w czasie kompilacji:

static_assert(floor<hours>(minutes{3}).count() == 0, "”); 

Co z tego?

+0

FWIW, oryginalna wersja (P0) artykułu Howarda jest dostępna tutaj: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0092r0.html –

Odpowiedz

9

Odpowiedź brzmi, że nie wszystkie operacje w procedurze kompilacji muszą być constexpr; tylko te , które są wykonywane w czasie kompilacji.

W przykładzie powyżej, operacje są:

hours t = duration_cast<hours>(d); 
if (t > d) {} // which is false, so execution skips the block 
return t; 

z których wszystkie mogą być wykonane w czasie kompilacji.

Jeśli, z drugiej strony, to było spróbować:

static_assert(floor<hours>(minutes{-3}).count() == -1, "”); 

byłoby dać błąd kompilacji mówiąc (za pomocą szczęk):

error: static_assert expression is not an integral constant expression 
     static_assert(floor<hours>(minutes{-3}).count() == -1, ""); 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
note: non-constexpr function 'operator--' cannot be used in a constant expression 
         --t; 
         ^
note: in call to 'floor(minutes{-3})' 
     static_assert(floor<hours>(minutes{-3}).count() == -1, ""); 

Podczas pisania kodu constexpr, ty muszą rozważyć wszystkie ścieżki poprzez kod.

P.S. Można naprawić proponowaną floor rutynowych wygląda następująco:

template <class To, class Rep, class Period, 
      class = enable_if_t<detail::is_duration<To>{}>> 
constexpr 
To floor(const duration<Rep, Period>& d) 
{ 
    To t = duration_cast<To>(d); 
    if (t > d) 
     t = t - To{1}; 
    return t; 
} 
0

zgodnie z zasadami n3597 i n3652 wyrażenia wewnątrz constexpr funkcji same nie muszą być stałe wyrażenia, o ile nie zmieniają stanu widocznego na całym świecie.

Jest przykładem

constexpr int f(int a) { 
    int n = a; 
    ++n;     // '++n' is not a constant expression 
    return n * a; 
} 
int k = f(4);   // OK, this is a constant expression. 
         // 'n' in 'f' can be modified because its lifetime 
         // began during the evaluation of the expression. 

Najprawdopodobniej są to zasady, które Howard Hinnant obserwowani podczas pisania papier wspomniałeś.

Aby pracować z kodem duration<T> w pytaniu, operator-- musiałaby zostać wykonana jako funkcja constexpr. Od constexpr zmiany w bibliotece nie były ostateczne, łatwo zrozumieć, w jaki sposób Howard mógł polegać na takiej zmianie.

+2

Sorry Ben, Marshall ma to dokładnie. Artykuły, o których wspomniałeś, są w C++ 14, a błąd ten popełniłem bardzo niedawno, używając C++ 14. –

Powiązane problemy