Schlüsselwort AUTO in c++0x++ , Diskussion, Erläuterung
-
Ich stand am Anfang auch kritisch gegenüber
varin C#, was eigentlich das Äquivalent zuautoin C++11 ist. Heute brauche ichvarin C# andauernd und bin immer enttäuscht, wenn eine Sprache sowas nicht anbietet.Customer customer = new Customer(); // vs. var customer = new Customer();Customer* customer = new Customer(); std::shared_ptr<Customer> customer = std::make_shared<Customer>(); // vs. auto customer = new Customer(); auto customer = std::make_shared<Customer>();Customer customer = new Customer(); // vs. // ACH ... mistIch verwende es zum Teil sogar schon für skalare Typen. Wenn man mal anfängt es zu verwenden, merkt man auch ganz schnell, dass der Typ sowas von überflüssig ist für das Verständnis. Man ist gar nicht daran interessiert. Zudem fördert es, dass man einen sinnvollen Variablennamen auswählt.
Hier z.B. ein kürzlich von mir geschriebenes Program (war ein kleiner Test):
#include <fstream> #include <iostream> #include <oppcl/oppcl.hpp> char const* const source = "__kernel void multiply(__global float* input, __global float* output)" "{" " size_t idx = get_global_id(0);" " output[idx] = input[idx] * input[idx];" "}"; void print_log(char const* txt) { std::clog << txt << '\n'; } int main() { print_log("Get platform..."); auto platform_id = oppcl::get_all_platforms().at(0); print_log("Get device..."); auto device_id = oppcl::get_all_devices(platform_id).at(0); float input_src[] = { 1, 2, 3, 4 }; float output_dest[4] = { }; print_log("Create queue and context..."); auto queue = oppcl::create_command_queue(device_id); auto ctx = oppcl::get_context(queue); print_log("Create input buffer..."); auto mem_input = oppcl::create_read_buffer<float>(ctx, 4); print_log("Create output buffer..."); auto mem_output = oppcl::create_write_buffer<float>(ctx, 4); print_log("Write to input buffer..."); oppcl::async_write(queue, mem_input, input_src, 4); print_log("Create program..."); auto program = oppcl::create_program(ctx, source); print_log("Build program..."); oppcl::build_program(program); print_log("Get kernel..."); auto kernel = oppcl::create_kernel(program, "multiply"); oppcl::wait_until_finished(queue); print_log("Set kernel arguments..."); oppcl::set_kernel_arg(kernel, 0, mem_input); oppcl::set_kernel_arg(kernel, 1, mem_output); print_log("Run kernel..."); oppcl::run_kernel(kernel, queue, 4); oppcl::wait_until_finished(queue); print_log("Read output buffer..."); oppcl::async_read(queue, mem_output, output_dest, 4); oppcl::wait_until_finished(queue); print_log("Print results..."); for(int i = 0; i < 4; ++i) { std::cout << output[i] << '\n'; } std::cin.get(); return 0; }oppcl::create_command_queuegibt z.B.oppcl::shared_handle<cl_command_queue>zurück. Aber ist das wirklich wichtig für das Verständnis des Programmes? Meiner Meinung nach nicht.Grüssli
-
Dravere schrieb:
Ich verwende es zum Teil sogar schon für skalare Typen.
Das wird halt dann interessant, wenn man keinen expliziten Typ als Rückgabewert hat, sondern z.B. nur eine Zahl. Dann nimmt man doch mal lieber unsigned oder float. Ansonsten stimme ich dir zu, bei (fast*) allem wo man eine Funktion nimmt die irgendwas zurückgibt, ist auto super.
* Mit Referenzen sollte man aufpassen, wenn man nur eine Referenz will, sonst wird das nämlich kopiert.
-
cooky451 schrieb:
* Mit Referenzen sollte man aufpassen, wenn man nur eine Referenz will, sonst wird das nämlich kopiert.
Wo ist das Problem? Wenn ich explizit eine Referenz haben möchte schreibe ich halt
auto&
Darauf müsste ich beim Ausschreiben des Typen genauso achten, ist also unabhängig von der auto-Geschichte.cooky451 schrieb:
Dravere schrieb:
Ich verwende es zum Teil sogar schon für skalare Typen.
Das wird halt dann interessant, wenn man keinen expliziten Typ als Rückgabewert hat, sondern z.B. nur eine Zahl.
Beispiel? Man hat doch immer einen expliziten Typen als Rückgabetyp. Und grade wenn das einer der implementatoin-defined Typen ist, ist auto erst recht gut - man hat dann genau den Typen den man braucht. groß/genau genug aber nicht zu groß/genau.
-
pumuckl schrieb:
cooky451 schrieb:
* Mit Referenzen sollte man aufpassen, wenn man nur eine Referenz will, sonst wird das nämlich kopiert.
Wo ist das Problem? Wenn ich explizit eine Referenz haben möchte schreibe ich halt
auto&
Ou, daran hatte ich gar nicht gedacht, das ist natürlich cool.

pumuckl schrieb:
cooky451 schrieb:
Das wird halt dann interessant, wenn man keinen expliziten Typ als Rückgabewert hat, sondern z.B. nur eine Zahl.
Beispiel? Man hat doch immer einen expliziten Typen als Rückgabetyp. Und grade wenn das einer der implementatoin-defined Typen ist, ist auto erst recht gut - man hat dann genau den Typen den man braucht. groß/genau genug aber nicht zu groß/genau.
Beispiel?
for (auto i = 0; ..)
-
cooky451 schrieb:
pumuckl schrieb:
cooky451 schrieb:
Das wird halt dann interessant, wenn man keinen expliziten Typ als Rückgabewert hat, sondern z.B. nur eine Zahl.
Beispiel? Man hat doch immer einen expliziten Typen als Rückgabetyp. [...]
Beispiel?
for (auto i = 0; ..)0 ist nicht nur einfach eine Zahl sondern hat einen Typ: int. auto verhält sich hier genauso wie Template-Argument-Deduction bei Funktionstemplates.
0 --> int 0L --> long int 0u --> unsigned int 0uL --> unsigned long int 0.0 --> double 0.f --> floatLässt man das u bei Ganzzahlen weg, schreibt dafür die Zahl aber in Hex hin, erhält man auch ggf eine Zahl eines vorzeichenlosen Typs.
Eine Sache kann auto aber mehr:
auto foo = {1,2,3}; // decltype(foo) --> initializer_list<int>Das klappt nur bei auto und nicht bei Funktionstemplates.
-
krümelkacker schrieb:
0 ist nicht nur einfach eine Zahl sondern hat einen Typ: int. auto verhält sich hier genauso wie Template-Argument-Deduction bei Funktionstemplates.
Ja, schon. Aber dann schreibst du wirklich statt "unsigned i = 0" "auto i = 0u"?
-
Nö, das habe ich nicht behauptet. Aber ich verwende schonmal entsprechende Suffixe. Blödes aber einfaches Beispiel:
bool is_odd(int z) { return z & 1u; }Damit erzwinge ich hier eine arithmetische Konvertierung int -> unsigned von z bevor & angewendet wird. Diese Konvertierung garantiert mir das Bitmuster eines 2er-Komplements; denn sonst könnte das bei negativen Zahlen und einer anderen Darstellung (1er Komplement) nach hinten losgehen. Die Bitoperationen bei negativen Werten sind einfach nicht klar festgelegt. Bei vorzeichenlosen Zahlen schon.
-
krümelkacker schrieb:
Nö, das habe ich nicht behauptet. Aber ich verwende schonmal entsprechende Suffixe. Blödes aber einfaches Beispiel:
bool is_odd(int z) { return z & 1u; }Damit erzwinge ich hier eine arithmetische Konvertierung int -> unsigned von z bevor & angewendet wird. Diese Konvertierung garantiert mir das Bitmuster eines 2er-Komplements; denn sonst könnte das bei negativen Zahlen und einer anderen Darstellung (1er Komplement) nach hinten losgehen. Die Bitoperationen bei negativen Werten sind einfach nicht klar festgelegt. Bei vorzeichenlosen Zahlen schon.
Aber täte
bool is_odd(int z) { return z%2==0; }nicht das besser tun? Weil man gar nicht um Bitgefrickel nachdenken muß, sondern eher in der Mathematik bleibt.
-
volkard schrieb:
nicht das besser tun? Weil man gar nicht um Bitgefrickel nachdenken muß, sondern eher in der Mathematik bleibt.
Wurde das nicht nur mit unsigned optimiert?

-
cooky451 schrieb:
Wurde das nicht nur mit unsigned optimiert?

Verwechselst Du das mit %1024?
-
volkard schrieb:
Aber täte
bool is_odd(int z) { return z%2==0; }nicht das besser tun?
Es war leider das erste Beispiel, was mir einfiel. Ich würde wahrscheinlich auch einfach z%2**!=**0 der Lesbarkeit wegen schreiben und auf schlaue Compiler vertrauen, die daraus wieder eine Bitfrickelei machen.

-
volkard schrieb:
cooky451 schrieb:
Wurde das nicht nur mit unsigned optimiert?

Verwechselst Du das mit %1024?
Ne, ich beziehe mich da auf http://www.c-plusplus.net/forum/294476