c ++ 0x унаследованный конструктор в шаблонах - PullRequest
5 голосов
/ 23 марта 2011

Вот класс foo:

template <typename T>
struct foo
{
    foo()
    {
        t = nullptr;
    }

    foo(T* p, bool flag)
    {
        t = p;
    }
private:
    T* t;
};

Вот класс бар:

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

Это правильный синтаксис для наследования конструкторов?Если я использую "using foo :: foo;"затем компилятор Visual C ++ 2010 умирает.Итак, в основном, как наследовать конструкторы от шаблонных классов в VC ++ 2010?

Ответы [ 4 ]

9 голосов
/ 24 марта 2011
template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

Чтобы этот синтаксический анализ выполнялся правильно, вам нужно вставить template перед foo<T>;, чтобы сообщить компилятору, что foo следует рассматривать как имя шаблона (он не может смотреть на foo<T>сказать себе, так как T неизвестно).Но использование ::template не разрешено в объявлении использования.Имя также не относится ко всем конструкторам bar: Вместо этого оно будет ссылаться на конкретную специализацию шаблона функции конструктора (T - аргумент шаблона) такого конструктора, как показано ниже

template<typename T>
foo();

Кроме того, в объявлении using недопустимо использовать template-id (например, foo<T>) в качестве имени (что фактически запрещает ему ссылаться на специализацию шаблона функции, с добавлением запрета на специализации шаблона функции преобразования имен, указанныйтоже), так что даже если вы исправите проблему синтаксического анализа, используя ::template (если это будет возможно), вы все равно выдадите ошибку на этом этапе.

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

  • Если класс был назван с использованием идентификатора шаблона (имяform foo<T>) и последняя часть соответствует имени шаблона (так, foo<T>::foo или TTP<T>::TTP с TTP, являющимся параметром шаблона шаблона).
  • Если последняя часть соответствует имени класса (так, foo::foo или T::T, где T является параметром шаблона).

Эти два дополнительных правила активны только в объявлении использования.И они, естественно, не присутствовали в C ++ 03.Другое правило, которое также присутствовало в C ++ 03: если конечная часть называет имя внедренного класса, то это квалифицированное имя также ссылается на конструктор:

  • foo::foo будет работать для него.Но с одним только этим правилом T::T (где T обозначает класс foo) не будет работать, потому что foo не имеет члена с именем T.

Для этого при наличии специальных правил вы можете написать

using foo<T>::foo;
using bar::foo::foo; // valid too

Второе также верно: foo - это имя внедренного класса, которое было введено в базовый класс.foo<T> и наследуется до bar.Мы ссылаемся на это имя как bar::foo, а затем добавляем последнюю часть foo, которая снова ссылается на введенное имя класса, чтобы обозначить конструктор (ы) `foo.

Теперь вы понимаете, почему исходное имя, которое вы пробовали, ссылается на специализацию шаблона функции конструктора (если это разрешено): потому что часть foo<T>::foo будет называть все конструкторы, а <T>, которыйпоследует, отфильтрует шаблон и передаст аргумент типа.

6 голосов
/ 24 марта 2011

Если ваш компилятор еще не поддерживает наследуемые конструкторы, но поддерживает переменные макросы, переменные шаблоны и ссылки на значения, и действительно удобный type_trait, вот действительно достойный обходной путь:

#include <type_traits>
#include <utility>
#include <ostream>

enum Color {Red, Blue};

#define USING(Derived, Base)                                 \
    template<typename ...Args,                               \
             typename = typename std::enable_if              \
             <                                               \
                std::is_constructible<Base, Args...>::value  \
             >::type>                                        \
    Derived(Args &&...args)                                  \
        : Base(std::forward<Args>(args)...) { }              \


template<typename Mixin>
class add_color
: public Mixin
{
    Color color;

public:
    USING(add_color, Mixin);

    friend std::ostream& operator<<(std::ostream& os, const add_color& x)
    {
        switch (x.color)
        {
        case Red:
            os << "Red";
            break;
        case Blue:
            os << "Blue";
            break;
        }
        os << ' ' << x.first << ' ' << x.second;
        return os;
    }
};

#include <string>
#include <iostream>

int main()
{
    add_color<std::pair<std::string, int>> x1("five", 5);
    std::cout << "x1 = " << x1 << '\n';
    add_color<std::pair<std::string, int>> x3;
    std::cout << "x3 = " << x3 << '\n';
    add_color<std::pair<std::string, int>> x4 = x1;
    std::cout << "x4 = " << x4 << '\n';
    std::pair<std::string, int> p;
    add_color<std::pair<std::string, int>> x5 = p;
    std::cout << "x5 = " << x5 << '\n';
}

Если вы не используетеПока нет is_constructible, основная идея работает без него, но «унаследованный конструктор» будет слишком жадным.

3 голосов
/ 23 марта 2011

вам не нужен второй параметр шаблона;

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo;
};

должен сделать

edit Я отказываюсь, что это работает на g ++ - 4.4.1, однакоэто должен быть правильный синтаксис, когда функция становится доступной

2 голосов
/ 23 марта 2011

Другие ответы уже проделали хорошую работу, объясняя, как работают наследующие конструкторы в C ++ 0x.Однако на момент написания этой статьи ни один компилятор не реализовал полностью весь набор функций C ++ 0x.К сожалению, это означает, что VC ++ 2010 еще не поддерживает наследующие конструкторы.

Стандарт C ++ 0x еще не опубликован.Окончательный проект стандарта будет завершен где-то в марте , но для публикации ISO потребуется еще несколько месяцев.В течение этого времени разработчики компиляторов разворачивают функции, поэтому они будут максимально совместимы с C ++ 0x, когда стандарт будет завершен.

Я считаю, что последняя версия GCC поддерживает наследующие конструкторы, так что если вам необходимопопробуйте сейчас, вы можете использовать это.Конечно, поддержка C ++ 0x является экспериментальной и может изменяться по мере обнаружения ошибок и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...