C++11: Constructor Wirrwar

OP Persönliche Seite #6154614
Lesenswert?

Hi,

ich versuche gerade eine C++11 Wrapper-Classe für eine C-Library (nicht 
von mir) zu schreiben.  Die C-Lib bietet float-Funktionen, und die 
Klasse ist:
1
class Float
2
{
3
public:
4
    ~Float();
5
    Float();
6
    Float (long);
7
    explicit Float (double);
8

9
    Float (const Float&);
10
    const Float& operator= (const Float&);
11
    Float (Float&&) = default;
12
    Float& operator= (Float&&) = default;
13
};

Die C-Lib stellt Initialisierungen aus long und double zur Verfügung, 
und offenbar will man nicht double in integer umwandeln (oder umgekehrt) 
bevor ein Float Objekt konstruiert wird.
1
Float func ()
2
{
3
    Float f;
4
    double x = 3.1e10;
5
    f = x;
6
    return f;
7
}

Gibt dann folgende Warnung für "f = x;":
1
warning: overflow in implicit constant conversion [-Woverflow]
und es wird Konstruktor Float(long) verwendet (seh ich am erzeugten 
Code).

Wie schafft man es, dass Float(double) zur Construction aus double 
verwendet wird?

Noch unverständlicher sind die Fehler, wenn es 'nen Constructor
1
Float(int);
gibt: Fehler für "f = x;"
1
error: converting to 'Float' from initializer list would use explicit constructor 'Float::Float(double)'
Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber 
das ist ein Fehler???  Die genennten Konstruktoren sind alle; 
initializer_list wird noch nichtmal included.

Und es gibt nen Fehler
1
error: initializing argument 1 of 'Float& Float::operator=(Float&&)'
Bei einer Zuweisung kann das Float-Objekt einfach kopieren werden wenn 
die rechte Seite nicht mehr gebraucht wird.

Gleicher Fehler mit "Float& Float::operator= (const Float&&);"
#6154665
Lesenswert?

Johann L. schrieb:
> Gibt dann folgende Warnung für "f = x;":warning: overflow in implicit
> constant conversion [-Woverflow]
> und es wird Konstruktor Float(long) verwendet (seh ich am erzeugten
> Code).
>
> Wie schafft man es, dass Float(double) zur Construction aus double
> verwendet wird?

Na du hast doch selbst vorgegeben, dass eine Konvertierung von double 
nur explizit erlaubt ist, von long dagegen auch implizit:

>     Float (long);
>     explicit Float (double);

Du machst hier eine implizite Konvertierung, also bleibt ihm nur der 
Konstruktor, der einen long annimmt.


Johann L. schrieb:
> Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber
> das ist ein Fehler???

Gleiches Thema: Du hast implizite Konvertierungen von double verboten, 
lässt hier dem Compiler aber keine andere Möglichkeit. Was soll der arme 
denn tun?
OP Persönliche Seite #6154723
Lesenswert?

Rolf M. schrieb:
> Johann L. schrieb:
>> Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber
>> das ist ein Fehler???
>
> Gleiches Thema: Du hast implizite Konvertierungen von double verboten,
> lässt hier dem Compiler aber keine andere Möglichkeit. Was soll der arme
> denn tun?

Wieso brauche ich eine implizite Konvertierung double wenn das Arhument 
bereits ein double ist?

Was ich haben will:

Für einen double soll Float(double) verwendet werden.

Für einen long (oder andere Integer, die ohne Verlust als long 
darstellbar sind), soll Float(long) verwendet werden.

Für alles andere darf momentan gerne ein Error kommen (außer für Float 
selbst natürlich und const Float& etc.).
OP Persönliche Seite #6154725
Lesenswert?

Wilhelm M. schrieb:
> Johann L. schrieb:
>> Das explicit bedeutet doch, dass der Konstructor nur dann genommen wird,
>> wenn das argument "double" ist, und sonst nicht.  Und genau das ist doch
>> der Fall?
>
> Nein.
>
> in "f = x;" muss der Compiler die rechte Seite nach Float (implizit)
> umwandeln. Und das explicit verhindert genau das.

Wieso das?

Es gibt einen Constructor Float(double) und es gibt Zuweisungen 
operator=(const Float&) und operator=(Float&&).

Muss ich operator= jetzt auch noch für alle erdenklichen Integer und 
double und float etc. implementieren?
#6154730
Lesenswert?

Johann L. schrieb:
> Wiese das?

Nochmal: die rechte Seite ist double. Und Du hast einen 
Kopier/Verschiebungszuweisungs-Op für Float. Also muss(!) der Compiler 
die recht Seite nach Float (implizit) umwandlen. Daher brauchst Du einen 
Typwandlungs-ctor. Den hast Du aber mit explicit ausgeschaltet.

Also entweder:

- nimm das explicit weg (wenn Du das Verhalten haben willst)

oder

- schreib einen passenden Kopierzuweisungs-Op (ggf. auch 
Verschiebungszuweisungs-Op, wenn Du das möchtest).
#6154733
Lesenswert?

Johann L. schrieb:
> Wieso brauche ich eine implizite Konvertierung double wenn das Arhument
> bereits ein double ist?

> Float f;
> double x = 3.1e10;
> f = x;

Die letzte Zeile ist eine Zuweisung, keine Initialisierung, und 
erfordert einen cast von double nach float. Dafür braucht es einen 
cast-operator, der wegen "explicit" nicht verfügbar ist.

Ein
1
Float f{3.1e10};
oder
1
Float f = 3.1e10;

ruft den Konstruktor auf, und funktioniert daher.

Oliver
OP Persönliche Seite #6154747
Lesenswert?

Oliver S. schrieb:
> Ein
>
1
Float f{3.1e10};
> oder
>
1
Float f = 3.1e10;
>
> ruft den Konstruktor auf, und funktioniert daher.

Mit
1
Float func ()
2
{
3
    Float f = 3.1e10;
4
    return f;
5
}

bekomme ich ohne Float(int) für "Float f = 3.1e10;"
1
warning: overflow in implicit constant conversion [-Woverflow]

und erzeugt wird ein Constructor für long, nicht für double.

Mit Float(int) bekomme ich für "Float f = 3.1e10;"
1
error: conversion from 'double' to 'Float' is ambiguous
2
note: candidates are:
3
note: Float::Float(int)
4
note: Float::Float(long int)
#6154777
Lesenswert?

Johann L. schrieb:
> Rolf M. schrieb:
>> Johann L. schrieb:
>>> Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber
>>> das ist ein Fehler???
>>
>> Gleiches Thema: Du hast implizite Konvertierungen von double verboten,
>> lässt hier dem Compiler aber keine andere Möglichkeit. Was soll der arme
>> denn tun?
>
> Wieso brauche ich eine implizite Konvertierung double wenn das Arhument
> bereits ein double ist?

Ja, eben. Das Argument ist double:
1
f = x;
Für Zuweisungen hast du nur einen Operator angegeben, der ein Float als 
Argument hat, also muss x erst in ein Float konvertiert werden, damit es 
im Anschluss nach f kopiert werden kann.
Nun gibt es zwei Arten der Konvertierung: Implizit und explizit. 
Implizit heißt, dass es konvertiert wird, ohne dass du ausdrücklich in 
deinem Code den Wunsch dazu äußern musst.
explizit heißt, dass du es angeben musst. Das wäre z.B. so möglich:
1
f = static_cast<Float>(x);

Da du den Konvertierkonstruktor Float(double) als explicit markiert 
hast, hast du damit gesagt, dass diese Konvertierung nur als explizite 
Konvertierung erlaubt ist, also mit einem Cast.

Johann L. schrieb:
> Es gibt einen Constructor Float(double)

Der ist aber als explicit markiert, und damit nimmst du dem Compiler die 
Möglichkeit, den in diesem Fall zu verwenden.

> Muss ich operator= jetzt auch noch für alle erdenklichen Integer und
> double und float etc. implementieren?

Kann man machen, je nachdem.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren