2010-07-08 3 views
3

Еще раз, я хотел бы C++ была сильнее typedef S:Как сделать работу типа шаблона в этом случае?

#include <vector> 

template<typename T> 
struct A { 
    typedef std::vector<T> List; 
}; 

template<typename T> 
void processList(typename A<T>::List list) { 
    // ... 
} 

int main() { 
    A<int>::List list; 
    processList<int>(list); // This works. 
    processList(list);  // This doesn't. 
} 

Очевидно, что компилятор видит list как std::vector<int> и не A<int>::List, поэтому он не может соответствовать его против A<T>::List, что, как ожидается.

В самом деле, это более длинное имя типа, часто повторяющееся, и это неприятность. Вместо того, чтобы позволить processList принять vector вместо этого, есть ли способ сделать операцию типа шаблона для меня?

ответ

5

Есть ли способ сделать работу типа шаблона для меня?

Нет, это то, что называется , не выводимый контекст.

Однако, зачем вам это нужно? Идиоматический способ передачи последовательностей вокруг по итератору:.

template<typename It> 
void processList(It begin, It end) { 
    typedef typename std::iterator_traits<It>::value_type T; 
    // .... 
} 

int main() { 
    A<int>::List list; 
    processList(list.begin(), list.end()); // works now 
    return 0; 
} 

(Обратите внимание, что в вашем вопросе, вы передаете vectorзначения, что плохая вещь, чтобы сделать для итераторов, это нормально и даже предпочтительнее)

Однако, если вы действительно отчаянным, вы можете иметь функцию вывести любой контейнер, принимая определенное количество аргументов шаблона:.

template<typename T, typename A, template<typename,typename> C> 
void processList(C<T,A>& cont) { 
    // .... 
} 

Обратите внимание, что это будет любой шаблон с двумя аргументами шаблона. OTOH, он не будет соответствовать контейнеру, например std::map, который имеет различное количество аргументов.

+0

Хм, хороший момент. Наверное, я не очень люблю «идиоматику», потому что это для внутреннего использования только внутри одного класса. Передавая (ссылка на ..., о которой я не упоминал в этом упрощенном примере), сама вещь делает более короткий код на сайте вызова. – Thomas

+0

Я передал вектор по значению для простоты примера. На практике я, конечно, передаю ссылку на const. Ваше обновление является опрятным; не то, что я буду использовать его (я не отчаянный), но хорошо иметь в виду. – Thomas

+1

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

0

Got it. Использование наследования для создания типа, который на самом деле разные:

template<typename T> 
class A : public std::vector<T> { 
}; 

Хорошо, что мне не нужно конструкторы не по умолчанию, в этом случае.

+0

хорошее решение - не знаю, почему вы были проголосованы – Elemental

+0

Потому что это ужасно: 'std :: vector' не имеет виртуального деструктора. –

+0

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

0

Существует простое решение в вашем случае:

template <class C> 
void processList(C const& list) 
{ 
    typedef typename C::value_type value_type; 
    BOOST_STATIC_ASSERT_MSG((boost::same_type< C, typename A<value_type>::List >), 
    NOT_A_A_LIST_TYPE, 
    (C, A<value_type>) 
); 
    // do your stuff 
} 

Обратите внимание, что C++ 0x приходит!

template <typename second> 
using TypedefName = SomeType<OtherType, second, 5>; 

Интересно, если это будет работать

template <typename value> 
using AList = typename A<value>::List;