开发者

Derived assignment operator and perfect forwarding

开发者 https://www.devze.com 2023-02-18 17:57 出处:网络
Consider this minimal example: include <iostream> struct foo { foo &operator=(const foo &) {

Consider this minimal example:

include <iostream>

struct foo
{
      foo &operator=(const foo &)
      {
              std::cout << "base copy assignment\n";
              return *this;
      }
      foo &operator=(foo &&)
      {
              std::cout << "base move assignment\n";
              return *this;
      }
};

struct bar: foo
{
      template <typename T>
      bar &operator=(T &&x)
      {
              std::cout << "derived generic assignment\n";
              foo::operator=(std::forward<T>(x));
              return *this;
      }
};

int main()
{
    bar b, c;
    b = c;
    b = bar{};
}

The output of this program is:

derived generic assignment
base copy assignment
base move assignment

whereas I would expect it to be:

derived generic assignment
base copy assignment
derived generic assignment
base move assignment

Or, in other words, it seems like the perfect forwarding of operator=() in bar is not kicking in case of move assignment: the base move assignment operator is called instead.

I've tried the same test with a simple member function and in that case the result is as I would expect (i.e., the开发者_C百科 perfectly-forwarded assignment in bar is always called before any of the base assignments). Also, with GCC 4.5 as opposed to the 4.6 pre-release I'm currently using, the behaviour is also as I would expect.

Is this an intended behaviour specific to assignment operators or is this a recent GCC bug?


I at first answered incorrectly. I believe the output you are getting is correct. There is an implicit generation of a move assignment operator in bar, and that is what is getting called in your second assignment. The implicit move assignment operator is a better match than your explicit generic one.

There is also an implicit copy assignment operator, but in this case the generic assignment operator is a better match because c is not const.

Elaboration:

The generation of an implicit move assignment operator is only inhibited if the user declares a copy assignment operator, move assignment operator, copy constructor, move constructor or destructor. None of these special members can be a template. [class.copy] enumerates the forms for each of these special members.

For example a move assignment operator for class X will have one of the following forms:

operator=(X&&);
operator=(const X&&);
operator=(volatile X&&);
operator=(const volatile X&&);

(any return type can be used).

The templated assignment operator in bar does not qualify as a special member. It is not a copy assignment operator nor a move assignment operator.

0

精彩评论

暂无评论...
验证码 换一张
取 消