Ich habe eine Klasse, in der ich die Kopier-/Verschiebungszuweisungsoperatoren nur dann aktivieren möchte, wenn ein Typparameter für die Klasse nothrow copy/move constructible ist. So versuche ich dies:enable_if mit Kopieren/Verschieben Zuweisungsoperator
#include <type_traits>
template<typename T>
struct Foobar {
Foobar(T value) : x(value) {}
Foobar(const Foobar &other) : x(other.x) {}
Foobar(Foobar &&other) : x(std::move(other.x)) {}
template<bool Condition = std::is_nothrow_copy_constructible<T>::value,
typename = typename std::enable_if<Condition>::type>
Foobar &operator=(const Foobar &rhs) {
x = rhs.x;
return *this;
}
template<bool Condition = std::is_nothrow_move_constructible<T>::value,
typename = typename std::enable_if<Condition>::type>
Foobar &operator=(Foobar &&rhs) {
x = std::move(rhs.x);
return *this;
}
T x;
};
int main() {
Foobar<int> foo(10);
Foobar<int> bar(20);
foo = bar;
foo.operator=(bar);
return 0;
}
Nun Clang gibt mir die folgende Fehlermeldung:
enable_if_test.cpp:31:9: error: object of type 'Foobar<int>' cannot be assigned because its copy assignment operator is implicitly
deleted
foo = bar;
^
enable_if_test.cpp:8:5: note: copy assignment operator is implicitly deleted because 'Foobar<int>' has a user-declared move
constructor
Foobar(Foobar &&other) : x(std::move(other.x)) {}
^
enable_if_test.cpp:32:9: error: call to deleted member function 'operator='
foo.operator=(bar);
~~~~^~~~~~~~~
enable_if_test.cpp:4:8: note: candidate function (the implicit copy assignment operator) has been implicitly deleted
struct Foobar {
^
enable_if_test.cpp:12:13: note: candidate function [with Condition = true, $1 = void]
Foobar &operator=(const Foobar &rhs) {
^
enable_if_test.cpp:19:13: note: candidate function [with Condition = true, $1 = void] not viable: no known conversion from
'Foobar<int>' to 'Foobar<int> &&' for 1st argument
Foobar &operator=(Foobar &&rhs) {
^
2 errors generated.
Nun, ich den expliziten Aufruf den Zuweisungsoperator enthalten die Seltsamkeit des Fehlers zu präsentieren. Es sagt nur, dass meine Vorlage eine Kandidatenfunktion ist und keinen Grund gibt, warum sie nicht gewählt wurde.
Meine Vermutung ist, dass, da ich einen Move-Konstruktor definiert, der Compiler implizit den Kopierzuweisungsoperator gelöscht hat. Da es implizit gelöscht wird, möchte es keine Vorlage instanziieren. Warum es sich so verhält, weiß ich allerdings nicht.
Wie kann ich dieses Verhalten erreichen?
(Anmerkung: Der tatsächliche Code hat berechtigte Gründe jedes der Elemente zu definieren, ich bin mir dessen bewusst, dass es sinnlos ist hier.)
T ist nicht in dem unmittelbaren Zusammenhang mit dem Zuweisungsoperator, so SFINAE nicht auftreten kann. Wenn Sie einen Dummy-Vorlagenparameter zu T hinzufügen, dann ersetzen Sie T für diesen Parameter für den Rest Ihrer Vorlagenargumente, es sollte funktionieren. – 0x499602D2
@ 0x499602D2 Ich kann deine Argumentation nicht ganz durcheinander bringen. Soweit ich das beurteilen kann, besteht das Problem im OP darin, dass Funktionsvorlagen nicht als spezielle Elementfunktionen betrachtet werden (mit Ausnahme des Standard-Ctors). – dyp
* "es will nicht einmal jede Vorlage instantiieren" * Nach allem, was ich weiß, werden Sie mit einem gelöschten 'operator = (Foo const &)' und einer Funktionsschablonenspezialisierung 'operator = (Foo const &)' enden . Und als letzter Ausweg werden Nicht-Template-Funktionen den Spezialisierungen von Funktionsvorlagen vorgezogen - dies wählt den gelöschten Operator aus. –
dyp