Casting bei Template-Funktionsaufruf: Was mache ich falsch und was ist in so einem Fall zu beachten?
Hallo, ich habe eine Frage zur C++-Programmierung.
Die Aufgabenstellung ist wie folgt:
3.2 Implementieren Sie ein Funktionstemplate „Add“ welches zwei übergebene Parameter unterschiedlichen Typs addieren kann, solange der +Operator für diese Variablen zur Verfügung steht. Welchen Vorteil bietet das Funktionstemplate gegenüber dem Überladen der Funktionen? Verwenden Sie als Übergabeparameter z.B. diese Parameterpaare. Rückgabewert soll auch ein Typparameter sein. Dieser ist dann allerdings immer beim Aufruf hinter die Funktion zu schreiben.
fVal2 = Add<float>(iVal1, iVal2);
Verifizieren Sie die Funktionsweise anhand verschiedener Datentypen und Konsolenausgaben.
Mein Template sieht so aus:
template <class Z>
Z Add(Z& a, Z& b) {
Z c = a + b;
return c;
};
Wenn ich jetzt in main die Funktion aufrufe:
float fval2 = Add<float>(i1, f2); // mit int i1, und float f2;
bekomme ich die Fehlermeldung:
'Z Add<float>(Z&, &)': cannot convert argument 1 from 'int' to 'Z&'.
Was mache ich falsch und was ist in so einem Fall zu beachten?
Danke im Voraus an alle.
Stan
1 Antwort
Vor C++17 hat man es i. d. R. so gemacht:
template <typname RESULT, typename T, typename U>
RESULT add(const T & t, const U & u) {
return t + u;
}
Falls du für beide Parameter "nur" einen einzigen Typen angibst, wird implizit gecastet, bevor die Argumente an die Funktion übergeben werden. Obacht also!
Seit C++17 geht es einfacher:
auto add(const auto & a, const auto & b) {
return a + b;
}
Beachte bitte in allen Codesnippets das "const"! Das ist enorm wichtig und verhindert unnötige Objekterzeugungen (Konstruktor- und Destruktoraufrufe). Falls dir das nicht klar ist, google unbedingt mal nach "const correctness". Das ist eines der wichtigsten Kernkonzepte von C++.
Zurück zu deiner Frage: Seit C++20 würde man die Aufgabe mit Concepts lösen, aber das wird dich im Moment evtl. noch überfordern.
Außerdem sei auf die type_traits verwiesen, mit denen du tolle Typprüfungen anstellen kannst.
Übrigens kannst du dir - anders als in der Aufgabenstellung behauptet - auch die Angabe des Rückgabetyps beim Aufruf sparen, indem du diese Syntax verwendest:
template <typename T, typename U>
auto add(const T & t, const U & u) -> decltype(t + u) {
return t + u;
}
Uuuund zu guter letzt, gibts noch static_assert, die du in deine Funktion knallen kannst, um Typzusicherungen zu erzwingen:
#include <type_traits>
auto add(const auto & a, const auto & b) {
using namespace ::std;
static_assert(is_integral<T>() || is_floating_point<T>());
static_assert(is_integral<U>() || is_floating_point<U>());
return a + b;
}
Und all das kannst du beliebig miteinander Kombinieren ... und gefühlt eine Million weitere type_traits nutzen.
Mit Concepts wird es kürzer und übersichtlicher, aber du musst dir vorher evtl. selbst eigene Konzepte definieren, was diich - wie gesagt - momentan evtl. noch überfordern wird.
Naja, viel Erfolg noch! :)