2015-08-27 44 views
13

Jestem nowy w programowaniu i zacząłem się uczyć o tym przy użyciu książki Zasady programowania i ćwiczenia z wykorzystaniem C++. Dzisiaj jestem tutaj, ponieważ mam pewne problemy w zrozumieniu funkcji constexpr. W rozdziale 8 autor wprowadza je w niektórych liniach i krótki przykład używając tych słów:Przekazywanie argumentów do funkcji constexpr

Funkcja reprezentuje obliczenia, a czasami chcemy wykonać obliczenia w czasie kompilacji. Powodem, dla którego obliczenie powinno być obliczone przez kompilator, jest zwykle unikanie tych samych obliczeń co miliony razy w czasie wykonywania.

Przekazujemy, że zamierzamy mieć funkcję ocenianą podczas kompilacji, deklarując funkcję jako funkcję constexpr. Funkcję constepxr można oszacować w czasie kompilacji, tylko jeśli jako argumenty podano jej wyrażenia stałe.

constexpr double xscale = 10; // scaling factors 
constexpr double yscale = 0.8; 
constexpr Point scale(Point p) { return { xscale*p.x, yscale*p.y }; }; 

Załóżmy, że punkt jest prostą strukturą z członami x i y reprezentującymi współrzędne 2D. Teraz, gdy podamy scale() argument o wartości scale(), zwraca on punkt o współrzędnych skalowanych zgodnie z czynnikami xscale i yscale. Na przykład:

void user(Point p1) { 

Point p2{10,10}; 

Point p3 = scale(p1); 
Point p4 = scale(p2) // p4 == {100,8} 

constexpr Point p5 = scale(p1); // error : scale(p1) is not a constant expression 
constexpr Point p6 = scale(p2); // p6 == {100,8}; 

Moje pytanie brzmi: Dlaczego możemy użyć p2 jako argument do scale()? Czy p2 jest traktowane jako wyrażenie stałe? A jeśli tak, dlaczego?

Czy elementy danych x i y można uznać za wyrażenia stałe?

Moja książka nie podaje zbyt wielu informacji, więc mam pewne problemy z tą koncepcją.

+0

Funkcja 'constexpr' nie * nie * wymaga, aby jej argumenty były wyrażeniami stałymi. To może być powszechne nieporozumienie. Jeśli wywołujesz taką funkcję z niestanowiącymi stałych argumentów, wynik jest również nie stały. Zasadniczo wyrażenie "funkcja constexpr" jest trochę mylące. Funkcja * 'foo' nie jest' constexpr' - * aplikacja * funkcji, 'foo (x, y)', jest stała jeśli i tylko jeśli 'x' i' y' są stałe –

Odpowiedz

12

Zasadniczo, funkcje constexpr mogą być wykonywane w czasie kompilacji lub w czasie pracy w zależności od kontekstu. Jest gwarantowane wykonywanie w czasie kompilacji tylko wtedy, gdy wszystkie jego parametry to constexpr, a jego wynik jest używany w kontekście wymagającym constexpr (np. Przypisanie do wartości constexpr, parametru szablonu lub, powiedzmy, rozmiaru tablicy w stylu c). W przeciwnym razie jest oceniany w czasie wykonywania jako dowolna inna funkcja. Więc p3 i p4 linie są wykonywane w czasie wykonywania, natomiast p5 daje błąd, ponieważ nie jest scale(p1)constexpr, a właściwie p6 powinny również daje błąd, chyba że dodasz constexpr definicji p2. Zobacz przykład here.

+0

Jak 'p6 'może być wykonane podczas kompilacji IF' p2' nie jest wyrażeniem stałym? – ForEveR

+0

Huh, szczerze mówiąc, jestem bardzo zaskoczony, że kompiluje 'p6'. Nawet coś tak prostego jak 'constexpr int plus2 (int x) {return x + 2; } '' int i = 0; constexpr int j = plus2 (i); 'nie kompiluje się w VS2015 lub GCC 5.1. Zmienię moją odpowiedź: – Rostislav

+0

'p6' również nie jest kompilowane przez gcc/clang. – ForEveR

3

Dlaczego możemy użyć p2 jako argumentu do scale()?

Ponieważ scale() jest napisane, aby zaakceptować niczego, co jest Point lub niejawnie zamienny do Point. W tym przypadku p2 jest typu Point. Dlatego może być użyty jako argument dla scale().

Czy p2 jest traktowane jako wyrażenie stałe? A jeśli tak, dlaczego?

p2 jest faktycznie zadeklarowana jako zmienna lokalna.Gdy jest on stosowany jako:

constexpr Point p6 = scale(p2);

jego wartość jest obliczana w czasie wykonywania przy użyciu wywołania funkcji, a więc jest to błąd. Aby to zadziałało, usuń słowo kluczowe constexpr. Jeśli chcesz, aby działało z constexpr, najpierw zadeklaruj p2 jako constexpr.

W następującym przypadku:

constexpr Point p5 = scale(p1);

p1 jest przekazywana jako argument do user() i może mieć dowolną wartość, która może być znana dopiero w czasie wykonywania, stąd ten błąd.

+0

Czy możesz podać cytat ze standardu o tym, dlaczego 'constexpr Point p6 = scale (p2);' powinien być skompilowany? Teraz wystąpi błąd kompilatora. – ForEveR

+0

@ForEveR Tak, nie kompiluje się i nie powinien. Zobacz moją poprawioną odpowiedź. Dzięki za dbałość o to :) – Rostislav

3

Wygląda na to, że jest w książce. To wygląda tak, jak powinno być

constexpr Point p2{10,10}; 

tylko w tym przypadku każdy nowoczesny kompilator nie da error na wezwanie

constexpr Point p6 = scale(p2); // p6 == {100,8}; 

to dlatego staramy się zainicjować constexpr zmienną wyniku funkcji, które będą oceniane w czasie wykonywania (jeśli p2 nie jest zadeklarowane jako constexpr).

+0

@NathanOliver W przypadku 'constexpr Point p2 {10,10};' to 'nie da'' błędu. – Pixelchemist

+0

ah okay. nie przeczytałem tego wystarczająco uważnie. – NathanOliver

Powiązane problemy