Можно ли унаследовать конструкторы копирования / перемещения с помощью объявления-использования в с ++17?

struct B {
  B(int) {}
  B(B const&) {}
};

struct D: B {
  using B::B;
};

int main(void) {
  B b(5);
  D d(b); // error
  return 0;
}

C++14 явно исключает конструкторы копирования / перемещения из унаследованных конструкторов в 12.9 [class.inhctor]/p3.

Для каждого конструктора, не являющегося шаблоном, в наборе кандидатов унаследованных конструкторов, кроме конструктора, не имеющего параметров, или конструктора копирования / перемещения, имеющего единственный параметр, конструктор неявно объявляется с теми же характеристиками конструктора, если только не существует объявленный пользователем конструктор с та же подпись в полном классе, где появляется объявление using, или конструктор будет конструктором по умолчанию, копировать или перемещать для этого класса.

Но я не смог найти подробных описаний в C++17. clang/gcc показывают, что конструкторы копирования / перемещения базового класса не наследуются. Может ли кто-нибудь указать, где это объясняется в стандарте? Спасибо.

2 ответа

Решение

Новая формулировка находится в [over.match.funcs] / 8:

Конструктор, унаследованный от типа класса C([class.inhctor.init]) с первым параметром типа "ссылка на cv1 P”(Включая такой конструктор, созданный из шаблона) исключается из набора функций-кандидатов при создании объекта типа cv2. D если список аргументов имеет ровно один аргумент и C ссылка связана с P а также P ссылка связана с D. [ Пример:

struct A {
  A();                                  // #1
  A(A &&);                              // #2
  template<typename T> A(T &&);         // #3
};

struct B : A {
  using A::A;
  B(const B &);                         // #4
  B(B &&) = default;                    // #5, implicitly deleted

  struct X { X(X &&) = delete; } x;
};

extern B b1;
B b2 = static_cast<B&&>(b1);            // calls #4: #1 is not viable, #2, #3, and #5 are not candidates
struct C { operator B&&(); };
B b3 = C();                             // calls #4

- конец примера ]

В вашем примере Bунаследованный конструктор копии исключается из набора кандидатов (этот конструктор имеет первый параметр ссылки типа на const B, список аргументов имеет ровно один аргумент - b, а также B а также D связаны со ссылками).

Цитируемый вами отрывок на самом деле не предотвращает наследование конструкторов копирования в C++14. Вместо этого подумайте об этом:

B(B const&, int = 42) {}

Это конструктор копирования, но он имеет два параметра. Отрывок исключает только конструктор копирования с одним параметром. И когда вы предоставляете оба аргумента, вы фактически можете инициализироватьD объект с этим конструктором.

g++ сообщения об ошибках дают некоторое представление.

note:   an inherited constructor is not a candidate for initialization from an expression of the same or derived type

Ага! Быстрый поиск в проекте стандарта обнаруживает это

Конструктор, унаследованный от типа класса C (http://eel.is/c++draft/class.inhctor.init), который имеет первый параметр типа "ссылка на cv1 P" (включая такой конструктор, созданный из шаблона), исключается из набора функций-кандидатов при создании объекта введите cv2 D, если список аргументов имеет ровно один аргумент и C связан со ссылкой с P, а P связан со ссылкой с D.

Другие вопросы по тегам