Forum: PC-Programmierung Zuweisung von std::arrays überladen


von Alex E. (tecnologic) Benutzerseite


Lesenswert?

Moin Zusammen,

ich habe in meinem Code mehrere Koordinatensysteme (abc, ab, dq) 
zwischen denen ich munter hin und her transformiere. Dafür habe ich mir 
3 Klassen geschrieben die die ganzen Operatoren überladen.
1
template < typename T>
2
class SystemABC;
3
template < typename T>
4
class SystemDQ;
5
template < typename T>
6
class SystemAlphaBeta;
7
8
/// Mit Operatoren wie diesem:
9
///< assignment operator with clark transformation
10
inline const SystemAlphaBeta& operator=(const SystemABC<T>& right)
11
{
12
  alpha = _2by3 * (right.a - (0.5f * right.b) - (0.5f * right.c)); 
13
  beta = _2by3 * ((sqrt3by2 * right.b) - (sqrt3by2 * right.c));
14
  return *this;
15
}

Das funktioniert wunderbar, aber ich habe auch Arrays der Vektoren wie:
1
std::array<SystemAlphaBeta<float>, 4> buffer

Wenn ich den Array des SystemAlphaBeta dem SystemABC zuweisen will muss 
ich eine nervige Schleife alla basteln:
1
 
2
// convert current samples with clark to statonary frame;
3
for(std::size_t i = 0; i < i_abc.size(); i++)
4
{
5
   i_alpha_beta[i] = i_abc[i];
6
}

Das nervt wäre aber noch zu verschmerzen. Bei komplizierterem, wie einer 
Zuweisung eines Arrays auf eine einzelne Instanz der Klasse um z.b. den 
Mittelwert auszuwerten, handle ich mir unnötig doppelten Code ein.

Dafür würde ich eigentlich gern den operator= der Template Instanz 
std::array<SystemAlphaBeta<float>, N> überladen. Geht sowas? Sonst fällt 
mir nur ein das Template der Klassen um einen Parameter mit der Array 
länge zu erweitern.

Gruß

Tec

: Bearbeitet durch User
von tictactoe (Gast)


Lesenswert?

Nein, das geht nicht. Man macht das ohne Schleife eher so:
1
#include <algorithm>
2
3
std::copy(i_abc.begin(), i_abc.end(), i_alpha_beta.end());

von mh (Gast)


Lesenswert?

tictactoe schrieb:
> Nein, das geht nicht. Man macht das ohne Schleife eher so:#include
> <algorithm>
>
> std::copy(i_abc.begin(), i_abc.end(), i_alpha_beta.end());

Kleinen Fehler korrigiert:
1
std::copy(i_abc.begin(), i_abc.end(), i_alpha_beta.begin());

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

mh schrieb:
> Kleinen Fehler korrigiert:
>
1
 std::copy(i_abc.begin(), i_abc.end(), 
2
> i_alpha_beta.begin());

Da stellt sich mir die Frage nutzt copy meinen Zuweisungsoperator, 
sprich die korrekte Transformation oder kopiert er einfach Speicher.

Die C++ Reference beschreibt die Implementierung nur recht schwammig.

In practice, implementations of std::copy avoid multiple assignments and 
use bulk copy functions such as std::memmove if the value type is 
TriviallyCopyable

Für mich bedeutet das, mir fliegt diese stelle im Code compilerabhängig 
um die Ohren. Je nachdem wie copy implementiert ist.

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

Ich will eigentlich nur sowas machen können:
1
std::array<SystemAlphaBeta<float>, 4> left_array =  std::array<SystemABC<float>, 4> right_array;

Die Zuweisung für
1
SystemAlphaBeta<float> left =  SystemABC<float> right;
ist implementiert und soll auch elementweise auf die Array Zuweisung 
angewendet werden.

von Timm R. (Firma: privatfrickler.de) (treinisch)


Lesenswert?

Hallo,

Dazu ein Gedanke als Anfänger:

überladen geht nicht, operator= ist Member.

Man kann aber doch eine Template Spezialisierung nur für den gewünschten 
Operator angeben? Also nicht die ganze Klasse spezialisieren, sondern 
nur den gewünschten operator= ?

vlg

 Timm

von Oliver S. (oliverso)


Lesenswert?

Tec N. schrieb:
> In practice, implementations of std::copy avoid multiple assignments and
> use bulk copy functions such as std::memmove if the value type is
> TriviallyCopyable
>
> Für mich bedeutet das, mir fliegt diese stelle im Code compilerabhängig
> um die Ohren. Je nachdem wie copy implementiert ist.

Tut es nicht.

http://en.cppreference.com/w/cpp/concept/TriviallyCopyable

Oliver

von mh (Gast)


Lesenswert?

Tec N. schrieb:
> Da stellt sich mir die Frage nutzt copy meinen Zuweisungsoperator,
> sprich die korrekte Transformation oder kopiert er einfach Speicher.
>
> Die C++ Reference beschreibt die Implementierung nur recht schwammig.
>
> In practice, implementations of std::copy avoid multiple assignments and
> use bulk copy functions such as std::memmove if the value type is
> TriviallyCopyable
>
> Für mich bedeutet das, mir fliegt diese stelle im Code compilerabhängig
> um die Ohren. Je nachdem wie copy implementiert ist.

Da hättest du etwas weiter lesen sollen.

Der Hinweis steht under "Notes" auf 
http://en.cppreference.com/w/cpp/algorithm/copy .
In dem Text ist TriviallyCopyable ein Link mit weiteren Erklärungen 
(http://en.cppreference.com/w/cpp/concept/TriviallyCopyable).
Unter Requirements steht unter anderem
> every copy assignment operator is trivial or deleted
Hier ist trivial wieder ein Link auf weitere Erklärungen
(http://en.cppreference.com/w/cpp/language/copy_assignment#Trivial_copy_assignment_operator).
Dort ist der erste Punkt
> it is not user-provided (meaning, it is implicitly-defined or defaulted) , , and 
if it is defaulted, its signature is the same as implicitly-defined (until C++14);
Also ist zumindest SystemAlphaBeta nicht TriviallyCopyable, da du einen 
eigen operator= lieferst und es wird kein memmove benutzt. Wenn du 
sicher gehen willst, dass deine Typen nicht TriviallyCopyable sind 
kannst du das mit dem type_trait is_trivially_copyable 
(http://en.cppreference.com/w/cpp/types/is_trivially_copyable) testen.

von mh (Gast)


Lesenswert?

Timm R. schrieb:
> Man kann aber doch eine Template Spezialisierung nur für den gewünschten
> Operator angeben? Also nicht die ganze Klasse spezialisieren, sondern
> nur den gewünschten operator= ?

Was man in namespace std machen darf ist ziemlich eingeschränkt 
(http://en.cppreference.com/w/cpp/language/extending_std). Im 
wesentlichen darf man nur in speziellen Fällen class templates 
spezialisieren.
Unter anderem gilt
> It is undefined behavior to declare a full specialization of any member function 
of a standard library class template
Man darf also operator= (member function) von std::array (standard 
library class template) nicht überladen.

Davon abgesehen müsste operator= erstmal eine template Memberfunktion 
sein, sonst ist man bei Overloading, was verboten ist.

von Oliver S. (oliverso)


Lesenswert?

Tec N. schrieb:
> Ich will eigentlich nur sowas machen können:
> std::array<SystemAlphaBeta<float>, 4> left_array =
> std::array<SystemABC<float>, 4> right_array;

Brauchst du das tatsächlich als vollen Zuweisungsoperator?

Wenn nicht, schreib dir halt eine Kopierfunktion. Da wird dann zwar 
deine Schleife von weiter oben drinstecken, aber im Endeffekt wird jede 
Implemetierung darauf hinauslaufen.

Oliver

von Timm R. (Firma: privatfrickler.de) (treinisch)


Lesenswert?

Hallo mh,

ups, wenn der Standard das für std:: verbietet, sollte man wohl die 
Finger davon lassen.

Trotzdem eine Frage:

mh schrieb:

> Davon abgesehen müsste operator= erstmal eine template Memberfunktion
> sein, sonst ist man bei Overloading, was verboten ist.

Der folgende operator = ist keine template Memberfunktion. Bedeutet das, 
dass Du sagst, dass das, was ich da mache, overloading und nicht 
specialization ist?
1
// Ich habe ... do something und sowas weggelassen, damit der Code compilierbar ist
2
template <typename T>
3
class test {
4
public:
5
    T& operator=(const T& in) {
6
        return daten;
7
    }
8
private:
9
    T daten;
10
};
11
12
template<>
13
std::string& test<std::string>::operator=(const std::string& in) {
14
    return daten;
15
}

vlg

 Timm

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

mh schrieb:
> Da hättest du etwas weiter lesen sollen.
>
> Der Hinweis steht under "Notes" auf
> http://en.cppreference.com/w/cpp/algorithm/copy .
> In dem Text ist TriviallyCopyable ein Link mit weiteren Erklärungen
> (http://en.cppreference.com/w/cpp/concept/TriviallyCopyable).

Stimmt hab ich nicht gelesen :) tl,dr.

Demnach sind alle beteiligten Klassen nicht TriviallyCopyable, dann ist 
std::copy ein sehr schöner Ansatz.

Timm R. schrieb:
> Der folgende operator = ist keine template Memberfunktion. Bedeutet das,
> dass Du sagst, dass das, was ich da mache, overloading und nicht
> specialization ist?
> // Ich habe ... do something und sowas weggelassen, damit der Code
> compilierbar ist
> template <typename T>
> class test {
> public:
>     T& operator=(const T& in) {
>         return daten;
>     }
> private:
>     T daten;
> };
>
> template<>
> std::string& test<std::string>::operator=(const std::string& in) {
>     return daten;
> }

Das wäre ja genau das was ich erreichen wollte. Dass man ein Template 
ohne Parameter spezialisieren kann, wusste ich gar nicht. Mal sehen was 
der GCC dazu sagt.

Wenn das keine bad practice ist werde ich das mal so versuchen.

Es geht ja auch darum das der zu implementierende Code so simpel wie 
möglich wird. Da ist = einfach charmant, wenn sich der Code/Compiler um 
den Rest kümmert.

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

1
template<typename T>
2
///< assignment operator with inverse clark transformation
3
inline const std::array<unit::SystemABC<T>, 4>& std::array<unit::SystemABC<T>, 4>::operator=(const std::array<unit::SystemAlphaBeta<T>, 4> &right)
4
{
5
  std::copy(right.begin(), right.end(), this->begin());
6
  return *this;
7
}
Dass stößt zumindest mal bei meinem GCC auf unmut.
1
../modules/unit/system_abc.hpp:126:146: error: invalid use of incomplete type 'struct std::array<unit::SystemABC<T>, 4>'
2
 inline const std::array<unit::SystemABC<T>, 4>& std::array<unit::SystemABC<T>, 4>::operator=(const std::array<unit::SystemAlphaBeta<T>, 4> &right)
3
                                                                                                                                                  ^
4
In file included from ../modules/control/current_control.cpp:19:0:
5
c:\eclipse\gnutools\arm-none-eabi\include\c++\7.1.0\array:94:12: note: declaration of 'struct std::array<unit::SystemABC<T>, 4>'
6
     struct array

Es sieht für mich aber so aus, als wenn ich an der Template Definition 
etwas falsch habe.

Die Variante mit float als Basis Typ geht aber auch nicht.
1
template<>
2
///< assignment operator with inverse clark transformation
3
inline const std::array<unit::SystemABC<float>, 4>& std::array<unit::SystemABC<float>, 4>::operator=(const std::array<unit::SystemAlphaBeta<float>, 4> &right)
4
{
5
  std::copy(right.begin(), right.end(), this->begin());
6
  return *this;
7
}
1
../modules/unit/system_abc.hpp:126:53: error: template-id 'operator=<>' for 'const std::array<unit::SystemABC<float>, 4>& std::array<unit::SystemABC<float>, 4>::operator=(const std::array<unit::SystemAlphaBeta<float>, 4>&)' does not match any template declaration
2
 inline const std::array<unit::SystemABC<float>, 4>& std::array<unit::SystemABC<float>, 4>::operator=(const std::array<unit::SystemAlphaBeta<float>, 4> &right)
3
                                                     ^~~
4
../modules/unit/system_abc.hpp:126:158: note: saw 1 'template<>', need 2 for specializing a member function template
5
 inline const std::array<unit::SystemABC<float>, 4>& std::array<unit::SystemABC<float>, 4>::operator=(const std::array<unit::SystemAlphaBeta<float>, 4> &right)

Nur kann ich die Beschwerde nicht verstehen das template hat 2 
Parameter! N Komma oder so habe ich auch nicht vergessen (glaub ich).

Hat noch jemand Ideen, sonst bleibe ich wohl bei der std::copy Variante, 
das läuft.

Danke dafür schon mal.

von Timm R. (Firma: privatfrickler.de) (treinisch)


Lesenswert?

Hallo,

ähmm, nur mal am Rande und auf die Gefahr hin, dass ich was ganz blödes 
sage: hat std::array überhaupt einen operator= ?

vlg

 Timm

von mh (Gast)


Lesenswert?

std::array hat einen vom compiler generierten operator=.

Timm R. schrieb:
> Der folgende operator = ist keine template Memberfunktion. Bedeutet das,
> dass Du sagst, dass das, was ich da mache, overloading und nicht
> specialization ist?
>
1
> template <typename T>
2
> class test {
3
> public:
4
>     T& operator=(const T& in) {
5
>         return daten;
6
>     }
7
> private:
8
>     T daten;
9
> };
10
> 
11
> template<>
12
> std::string& test<std::string>::operator=(const std::string& in) {
13
>     return daten;
14
> }
15
>
Ich würd sagen, dass das eine Spezialisierung der Klasse test<T> für T = 
std::string ist. operator= ist in diesem Fall kein Memberfunktions 
Template.

Wenn operator= ein Template wäre und du möchtest es spezialisieren, 
sieht das ungefähr so aus (keine Garantie für Korrektheit)
1
template <typename T>
2
class test {
3
public:
4
    template <typename U>
5
    T& operator=(const U& in) {
6
        return daten;
7
    }
8
private:
9
    T daten;
10
};
11
 
12
template <>
13
template <>
14
std::string& test<std::string>::operator=<std::string>(const std::string& in) {
15
    return daten;
16
}
Wenn du die Methode spezialisierst, musst du auch die Klasse 
spezialisieren.

Und bitte schreibe niemals einen operator=, der etwas anderes als *this 
zurück liefert.

von tictactoe (Gast)


Lesenswert?

Was du, glaube ich, machen darfst, ist eine Spezialisierung der Klasse 
für deinen eigenen Typ:
1
namespace std {
2
template<class T, size_t N>
3
class array<unit::SystemABC<T>, N> {
4
  // hier jetzt alles was fuer std::array vorgeschrieben ist
5
  // wie begin(), end(), size(), etc.
6
  //...
7
8
  // und dazu noch
9
  array& operator=(const array<unit::SystemAlphaBeta<T>, N> &right) {
10
    // ...
11
    return *this;
12
  }
13
  // dann brauchst du aber auch Default-Assignment:
14
  array& operator=(const array &right) {
15
    // ...
16
    return *this;
17
  }
18
};
19
}
Voraussetzung ist, dass die vom Standard vorgegebenen Member-Funktionen 
wie vom Standard definiert verhalten.

Ich würde aber die Finger davon lassen und bei std::copy bleiben.

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

tictactoe schrieb:
> Was du, glaube ich, machen darfst, ist eine Spezialisierung der Klasse
> für deinen eigenen Typ:
>
1
> namespace std {
2
> template<class T, size_t N>
3
> class array<unit::SystemABC<T>, N> {
4
>   // hier jetzt alles was fuer std::array vorgeschrieben ist
5
>   // wie begin(), end(), size(), etc.
6
>   //...
7
> 
8
>   // und dazu noch
9
>   array& operator=(const array<unit::SystemAlphaBeta<T>, N> &right) {
10
>     // ...
11
>     return *this;
12
>   }
13
>   // dann brauchst du aber auch Default-Assignment:
14
>   array& operator=(const array &right) {
15
>     // ...
16
>     return *this;
17
>   }
18
> };
19
> }
20
>
> Voraussetzung ist, dass die vom Standard vorgegebenen Member-Funktionen
> wie vom Standard definiert verhalten.
>
> Ich würde aber die Finger davon lassen und bei std::copy bleiben.

Das ist mir wirklich zu heiß, das versteht kein anderer mehr und ich in 
5 Jahren wahrscheinlich auch nicht.

mh schrieb:
> Wenn operator= ein Template wäre und du möchtest es spezialisieren,
> sieht das ungefähr so aus (keine Garantie für Korrektheit)template
> <typename T>
> class test {
> public:
>     template <typename U>
>     T& operator=(const U& in) {
>         return daten;
>     }
> private:
>     T daten;
> };
>
> template <>
> template <>
> std::string& test<std::string>::operator=<std::string>(const
> std::string& in) {
>     return daten;
> }
1
template<size_t N>
2
template<typename T>
3
std::array<unit::SystemAlphaBeta<T>, N>& std::array<unit::SystemAlphaBeta<T>, N>::operator=(const std::array<unit::SystemABC<T>, N>& right)
4
{
5
  return *this;
6
}
7
8
eribt: invalid use of incomplete type 'struct std::array<unit::SystemAlphaBeta<T>, N>'
Muss ich wirklich alles voll spezifizieren also Arraylänge N und den 
Basistypen T auch?

von Timm R. (Firma: privatfrickler.de) (treinisch)


Lesenswert?

Hallo,

mh schrieb:
> Und bitte schreibe niemals einen operator=, der etwas anderes als *this
> zurück liefert.

versprochen!

> Ich würd sagen, dass das eine Spezialisierung der Klasse test<T> für T =
> std::string ist. operator= ist in diesem Fall kein Memberfunktions
> Template.

Wenn das eine Spezialisierung der Klasse wäre, wäre dann Folgendes nicht 
fehlerhaft wegen Redefinition?
1
template <typename T>
2
class test {
3
public:
4
    test& operator=(const T& in) {
5
        return *this;
6
    }
7
    
8
    test& gleich(const T& in) {
9
        return *this;
10
    }
11
private:
12
    T daten;
13
};
14
15
template <>
16
test<std::string>& test<std::string>::operator=(const std::string& in) {
17
    std::cout << "String Spezialisierung\n";
18
    return *this;
19
}
20
21
template <>
22
test<std::string>& test<std::string>::gleich(const std::string& in) {
23
    std::cout << "String Spezialisierung\n";
24
    return *this;
25
}

vlg

 Timm

von Timm R. (Firma: privatfrickler.de) (treinisch)


Lesenswert?

Hallo,

Tec N. schrieb:

> eribt: invalid use of incomplete type 'struct
> std::array<unit::SystemAlphaBeta<T>, N>'
> [/c]
> Muss ich wirklich alles voll spezifizieren also Arraylänge N und den
> Basistypen T auch?

du solltest es eh nicht machen, wenn der Standard sagt, dass es böse ist 
und du weißt ja schon, dass die Standardoperation passt.

Aber: Ich glaube nicht, dass es geht. Das was ich vorgeschlagen habe, 
egal ob es sich nun um class specialization handelt oder um function 
specialization, geht nur mit members die auch deklariert sind. Implizite 
members kann man so nicht spezialisieren und = ist bei array implizit, 
wie mh bestätigt.



vlg

 Timm

: Bearbeitet durch User
von Alex E. (tecnologic) Benutzerseite


Lesenswert?

Timm R. schrieb:
>> eribt: invalid use of incomplete type 'struct
>> std::array<unit::SystemAlphaBeta<T>, N>'
>> [/c]
>> Muss ich wirklich alles voll spezifizieren also Arraylänge N und den
>> Basistypen T auch?
>
> du solltest es eh nicht machen, wenn der Standard sagt, dass es böse ist
> und du weißt ja schon, dass die Standardoperation passt.
>
> Aber: Ich glaube nicht, dass es geht. Das was ich vorgeschlagen habe,
> egal ob es sich nun um class specialization handelt oder um function
> specialization, geht nur mit members die auch deklariert sind. Implizite
> members kann man so nicht spezialisieren und = ist bei array implizit,
> wie mh bestätigt.

Sehe ich auch so. Danke für die Hilfe.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.