Как выглядит определение (тело) унаследованного конструктора?

Из моего чтения ответов на SO и Ссылка на ссылку

Унаследованные конструкторы эквивалентны пользовательским конструкторам с пустым телом и списком инициализатора члена, состоящим из одного вложенное имя спецификатор, который передает все свои аргументы в конструктор базового класса.

Я пришел к выводу, что ниже классы D а также E должен вести себя одинаково

#include <string>
#include <utility>
using namespace std;

class B
{
public:
B(string&& a) : a(move(a))
{
}

string a;
};

class D : public B
{
public:
using B::B;
};

class E : public B
{
public:
E(string&& a) : B(a)
{
}
};

string foo()
{
return "bar";
}

int main()
{
D d = foo();//This compiles
E e = foo();//This does not compile
return 0;
}

E e = foo() по ошибке не компилируется, так как Bконструктор принимает только string&&, Тем не мение, D d = foo() проходит нормально. Это почему?
Используется компилятор clang3.5.

РЕДАКТИРОВАТЬ: Кроме того, как объяснено в этом ответ, идеальный способ пересылки не заменяет наследование конструкторов. Итак, как именно выглядит тело?

2

Решение

Однако D d = foo () проходит нормально. Это почему?

Так как using B::B эффективно передает временную строку прямо в Bконструктор, где его еще можно связать аля && (то есть его категория стоимости все еще xvalue), затем выполняет любую дополнительную инициализацию производного класса (если были другие члены данных, VDT и т. д.). Это очень желательно, так как смысл использования конструкторов базового класса состоит в том, чтобы разрешить одинаковое использование клиента.

(Это контрастирует с E(string&&)внутри которого, где по имени a параметр больше не считается значением xvalue (временно истекающим), готовым для передачи B::B.)

(Если вы этого еще не сделали, вы можете посмотреть наstd::forward) [http://en.cppreference.com/w/cpp/utility/forward] тоже … это помогает с идеальной передачей аргументов)

2

Другие решения

Формулировка стандарта о том, как выглядит определение унаследованного конструктора в производном классе, немного более явна, чем то, на что ссылается описание cppreference, но ключевая фраза в последнем выдвигает все свои аргументы. Другими словами, категория значений аргументов сохраняется, что ваше определение E не делает, и, следовательно, не компилируется.

От N3337, §12.9 / 8 [Class.inhctor]

... Неявно определенный наследующий конструктор выполняет набор инициализаций класса, который будет выполнен встроенным конструктором, написанным пользователем для этого класса с мем-инициализатора-лист только чей мем-инициализатор имеет мем-инициализатор-идентификатор который называет базовый класс, обозначенный в вложенное имя спецификатор из используя декларирование и список_выражений как указано ниже, и где составной оператор в его теле функции пуст (12.6.2). Если этот пользовательский конструктор будет плохо сформирован, программа будет некорректно сформирована. Каждое выражение в список_выражений имеет форму static_cast<T&&>(p), где p это имя соответствующего параметра конструктора и T это объявленный тип p,

Таким образом, аргументы конструктора отлично перенаправляются в соответствующий унаследованный конструктор (std::forward (§20.2.3) указано вернуть static_cast<T&&>(p)точно так же, как и описание выше). В зависимости от объявленного типа параметра конструктора свертывание ссылок происходит, как описано в этот ответ.

В твоем случае, [T=string&&] и бросок дает string&& опять же, который может связываться с Bпараметр. Чтобы соответствовать этому поведению в E вы должны переписать конструктор как

E(string&& a) : B(static_cast<string&&>(a))
{
}
2

По вопросам рекламы [email protected]