jeudi 16 avril 2015

enable_if with copy/move assignment operator

I have a class in which I want to enable the copy/move assignment operators only if a type parameter to the class is nothrow copy/move constructible respectively. So I tries this:



#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;
}


Now, Clang gives me the following error:



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.


Now, I included the explicit call to the assignment operator to showcase the weirdness of the error. It just says that my template is a candidate function and gives no reason for why it is not chosen.


My guess here is that since I defined a move constructor, the compiler implicitly deleted the copy assignment operator. Since it is implicitly deleted, it doesn't even want to instantiate any template. Why it behaves like this I do not know, however.


How can I achieve this behavior?


(Note: The actual code has legitimate reasons to define each of the members, I'm aware that it is useless here.)


Aucun commentaire:

Enregistrer un commentaire