Шаблоны Variadic и ожидаемая ошибка типа

Я работаю (в основном в учебных целях) над собственной реализацией tuple и только что столкнулся с проблемой. У меня есть следующий код:

namespace Rose
{
    template<typename T>
    struct RemoveReference
    {
        typedef T Type;
    };

    template<typename T>
    struct RemoveReference<T &>
    {
        typedef T Type;
    };

    template<typename... Elems>
    class Tuple;

    template<typename First, typename... Elems>
    class Tuple<First, Elems...>
    {
    public:
        Tuple(First a, Elems... more)
            : More(more...), Element(a)
        {
        }

        Tuple<First, Elems...> & operator=(const Tuple<RemoveReference<First>::Type,
                                           RemoveReference<Elems>::Type...> & rhs)
        {
            this->Element = rhs.Element;
            this->More = rhs.More;

            return *this;
        }

    private:
        Tuple<Elems...> More;
        First Element;
    };

    template<typename Only>
    class Tuple<Only>
    {
    public:
        Tuple(Only a) : Element(a)
        {
        }

        Tuple<Only> & operator=(const Tuple<RemoveReference<Only>::Type> & rhs)
        {
            this->Element = rhs.Element;

            return *this;
        }

    private:
        Only Element;
    };
}

int main()
{
    Rose::Tuple<int, float, int> t(1, 1.f, 2);
}

Что вызывает следующую ошибку (их больше, но это важно):

ошибка: несоответствие типа/значения в аргументе 1 в списке параметров шаблона для 'template struct Rose::Tuple' ошибка: ожидался тип, получено 'Rose::RemoveReference::Type'

Я не очень понимаю, о чем это. Черта RemoveReference работает, когда используется отдельно.

Вот два теста:

Я пробовал этот код с G++ 4.6.1, 4.5.1 и Clang++ 2.9.

В чем причина появления этих ошибок?


person Griwes    schedule 27.04.2012    source источник
comment
может быть, вам не хватает простого typename?   -  person juanchopanza    schedule 28.04.2012
comment
Вы имеете в виду в параметрах шаблона Tuples списки параметров?   -  person Griwes    schedule 28.04.2012
comment
Я мало знаю о правилах вариативных шаблонов, но вы уверены, что можете сделать RemoveReference<Elems>, когда Elems равно typename... Elems?   -  person Seth Carnegie    schedule 28.04.2012
comment
@SethCarnegie, поэтому я поставил ... после всего выражения.   -  person Griwes    schedule 28.04.2012
comment
@juanchopanza, ура, сработало. Не могли бы вы опубликовать ответ, чтобы я мог его принять?   -  person Griwes    schedule 28.04.2012
comment
@Гривес только что сделал. Хотя не очень полный ответ...   -  person juanchopanza    schedule 28.04.2012
comment
Tuple<Only> & operator=(const Tuple<typename RemoveReference<Only>::Type> & rhs) для вложенного типа?   -  person AJG85    schedule 28.04.2012
comment
@Гривес, что это делает? Как я уже сказал, я мало знаю о ВТ.   -  person Seth Carnegie    schedule 28.04.2012
comment
@SethCarnegie, он распаковывает параметры. Например: если вы используете класс как A<int, int, float>, а определение класса — template<typename... Args> class A {...};, то Args..., используемый в качестве списка параметров шаблона, становится int, int, float.   -  person Griwes    schedule 28.04.2012
comment
@Griwes Я знал это, но почему это работает после выражения RemoveReference<>::Type? Похоже, вы пытаетесь рассматривать int, int, float как один тип, чтобы удалить из них &. И RemoveReference<>::Type это только один тип, не так ли?   -  person Seth Carnegie    schedule 28.04.2012
comment
@SethCarnegie, нет, в данном конкретном случае RemoveReference<Elems>::Type... (например, Elems равно int, int, float) становится RemoveReference<int>::Type, RemoveReference<int>::Type, RemoveReference<float>::Type.   -  person Griwes    schedule 28.04.2012
comment
@Griwes Я предполагаю, что это функция C++, которая превращает одно выражение с ... перед ним и основанное на пакете имен типов в несколько выражений? Это круто и удобно.   -  person Seth Carnegie    schedule 28.04.2012


Ответы (1)


RemoveReference<T>::Type — это зависимый тип, поэтому здесь нужно добавить typename:

        Tuple<First, Elems...> & operator=(const Tuple<typename RemoveReference<First>::Type,
                                                       typename RemoveReference<Elems>::Type...> & rhs)

и, возможно, в других местах.

person juanchopanza    schedule 27.04.2012
comment
Собственно, все ошибки исправлены. См. здесь. Кажется, я действительно должен попытаться поставить typename во все возможные места, прежде чем пытаться что-то еще. Кроме того, я думаю, вы имели в виду RemoveReference<T>::Type, а не tuple<T>::type в самом начале своего ответа, не так ли? - person Griwes; 28.04.2012
comment
@Griwes, да, я имел в виду RemoveReference. Спасибо за исправление. - person juanchopanza; 28.04.2012