2013-04-13 2 views
4

Кажется, что это должно быть очень просто, но я играл и не нашел решение, которое я ищу, так вот:C++ `using` команда для псевдонима типа в классе шаблонов

у меня есть следующие структуры (упрощено для иллюстративных целей, конечно):

template<typename T> 
struct test 
    { 
    using L = std::list<T>; 
    L::iterator a; 
    }; 

Теперь, это бросает ошибку:

error: need 'typename' before 'test<T>::K::iterator' because 'test<T>::K' is a dependent scope 

два способа, которые я нашел фиксацию его до сих пор является менее чем идея л:

1) добавить имяТип перед любым использованием L:

template<typename T> 
struct test 
    { 
    using L = std::list<T>; 
    typename L::iterator a; 
    }; 

Я предпочел бы избежать дополнительной подробности этого, если это возможно.

2) добавить еще используя утверждение целевой итератор непосредственно:

template<typename T> 
struct test 
    { 
    using L = std::list<T>; 
    using iter = typename L::iterator; 
    iter a; 
    }; 

Но это потребует того, чтобы сделать то же самое для каждого итератора я хотел использовать, если я хотел бы также получить доступ к const_iterator и т. д. и т. д., и я бы предпочел не указывать кучу использования операторов.

Итак, есть ли способ, чтобы написать заявление, используя то позволяет мне писать:

L::iterator a; 
L::const_iterator b; 
... 

Спасибо!

ответ

14

typename должен быть там, но вы можете использовать несколько шаблонов псевдоним утилиты, чтобы избежать определения нового iter Типу каждый раз:

template<typename C> 
using Iterator = typename C::iterator; 

template<typename C> 
using ConstIterator = typename C::const_iterator; 

template<typename T> 
struct test 
{ 
    using L = std::list<T>; 
    Iterator<L> i; 
    ConstIterator<L> ci; 
}; 
+0

Это лучше, чем мой мета-подход, +1! – Yakk

+0

Спасибо за ответ! В свете того, что я не смог сделать это по-своему, это выглядит самым чистым способом: – jsdw

+0

@lytnus: Рад, что это помогло :) –

2

Нет, нет. Все зависимые типы должны либо быть предварены typename, либо вводиться через предисловие с typename.

Теперь вы можете создать list_iter<T>using declartion где:

template<typename T> 
using list_iter = typename std::list<T>::iterator; 

или даже мета-ИТЭР, используя оператор:

template<template<typename>class container, typename T> 
using iter = typename container<T>::iterator; 
template<template<typename>class container, typename T> 
using const_iter = typename container<T>::const_iterator; 

, который позволит вам сделать:

struct test { 
    using L = std::list<T>; 
    iter<std::list,T> a; 
}; 

, где я «скрыл» typename в using за пределами struct.

В стороне, в 99% случаев std::list - неправильный контейнер.

+1

Я думаю, что это не будет работать, потому что 'станд :: list' также принимает дополнительный параметр типа распределителя (который имеет аргумент по умолчанию) –

+0

Спасибо за ваш ответ!Что касается использования списка, это будет потенциально очень большой список символов, которые часто нужно удалять или вставлять в местах, сохраненных где-то в другом месте (поэтому перемещение списка для их поиска не вызывает беспокойства); Я думаю, что это один из этих 1% случаев. – jsdw

+0

Если вы переходите на «список», чтобы найти их перед их удалением, и они не все кластеризованы в начале списка или рядом с ним, тогда «вектор» остается больше эффективный. Для 'list', чтобы выиграть, вам в основном нужно добавлять и удалять элементы из него * без прохождения, чтобы найти элементы *, потому что стоимость« смещения »элементов вниз в« вектор »часто дешевле, чем стоимость пересекая «список»! (дорогие для перемещения (т. е. без перемещения и большие копии) элементы также могут сделать «список» более заманчивым, но даже тогда «deque» выигрывает ...) Если вы не профилировались, вы ошибаетесь. – Yakk