Работают ли наследующие конструкторы с шаблонами в C ++ 0x? - PullRequest
23 голосов
/ 13 сентября 2011

В C ++ 0x вы можете использовать ключевое слово using для наследования конструкторов, например:

class B { B(int) {} };

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

Который неявно объявит конструктор A(int). Работает ли это с шаблонами?

class B { B(int) {} };

template<class T> class A : public T { using T::T; };

В T::T я ожидаю, что компилятор вычислит левую руку T, поскольку использование оператора области видимости для аргументов шаблона является нормальным, но выяснение, что правая рука T является конструктором, является особым случаем. На самом деле кажется, что есть двусмысленность: что если у меня есть метод с именем T в B, к которому я пытаюсь добавить перегрузки в A (именно так компилятор интерпретирует такое объявление использования перед C +) + 0x)

Ответы [ 2 ]

10 голосов
/ 14 сентября 2011

Да, это работает, и причина кроется в механизме поиска имени.Механизм, в котором работает объявление наследующих конструкторов, прост: если имя используемого объявления ссылается на конструкторы базового класса, это объявление наследующих конструкторов.На 3.4.3.1 [class.qual] p2 мы находим:

В поиске, в котором конструктор является приемлемым результатом поиска, а спецификатор вложенного имени назначает класс C

  • , если имя, указанное после спецификатора вложенного имени, при поиске в C, является именем введенного класса C (пункт 9) или
  • в объявлении использования (7.3.3) это объявление члена, если имя, указанное после спецификатора вложенного имени, совпадает с идентификатором или именем шаблона простого идентификатора шаблона в последнем компоненте спецификатора вложенного имени

вместо этого считается, что имя присваивает имя конструктору класса C.

Этот абзац работает с определениями конструкторов классов, и это также абзац, который делаетнаследование объявлений конструктора работает.Второй пункт применяется в этом случае:

struct B {
  B(int) { }
};

typedef B mytype;

struct A : B {
  // "name ... is the same as the identifier ... in the last component ..."
  using mytype::mytype;
};


template<typename T> using same = T;

struct C : B {
  // "name ... is the same as the template-name ... in the last component ..."
  same<B>::same;
};

Последний пример также полезен в следующих случаях:

template<template<typename> class Base>
struct X : Base<int> {
  using Base<int>::Base;
};

В итоге:

  • Первый маркер выше - это семантическое правило - если имя после вложенного спецификатора имени относится к введенному имени класса (B::B или mytype::B), то оно будет преобразовано для ссылки на конструктор (ы).

  • Второй маркер является синтаксическим правилом - имена просто должны совпадать - в противном случае их значение не имеет значения - в аргументе шаблона, предоставленном * 1032, мог быть элемент с именем Base*, например, как показано ниже, но объявление using все равно импортирует конструкторы и делает not имя члена Base:

    template<typename T> struct D { private: T Base; };
    X<D> x; // valid, the private member is *not* touched!
    
7 голосов
/ 13 сентября 2011

Да, похоже, из стандартного (февраль 2011 года) раздела 12.9:

template< class T >
struct D : T {
using T::T; // declares all constructors from class T
~D() { std::clog << "Destroying wrapper" << std::endl; }
};

Шаблон класса D оборачивает любой класс и пересылает все его конструкторы при написаниисообщение в стандартный журнал всякий раз, когда объект класса D уничтожается.- конец примера

Еще один момент, на который следует обратить внимание, хотя стандарт разрешает, согласно этому списку , только один компилятор, IBM XLC ++, поддерживает эту функцию в версии выпуска.В настоящее время GCC поддерживает его только с патчем.

Редактировать: AJG85 указал, что T в шаблоне всегда ссылается на заполнитель, поэтому 'using T :: T' всегда ссылается на аргумент шаблона.

...