2009-10-28 4 views
2

Дано:Переходя зЬй :: вектора для любого типа функции

template<typename T> class A { 
    B b; 
    std::vector<T> vec1; 
    std::vector<T> vec2; 
} 

я хотел B иметь функцию-член, заполняющую(), который принимает ссылку на те векторы и заполняющую vec2 со значениями T в зависимости от некоторой информации, содержащейся в b.
Один из способов сделать это перегружает заполнения() для каждого возможного аргумента Т:

fill(const std::vector<float>& a, std::vector<float>& b) 

и так далее, но это будет означать, много ненужного дублирования в операции одинаковы для всех возможных Т. Внутри из fill() Я мог бы использовать vector :: value_type для вычислений, но я не знаю, как объявить его таким образом, что он принимает каждый тип std :: vector. Очевидным способом было бы использовать свободную функцию с шаблонами. Есть ли более простой способ сделать это?

ответ

5

Templatize B.

template<typename T> class B { 
    void fill(const std::vector<T>& a, std::vector<T>& b) { } 
}; 

template<typename T> class A { 
    B<T> b; 
    std::vector<T> vec1; 
    std::vector<T> vec2; 
} 

Если вы не хотите templatize B, затем templatize функцию заливки:

class B { 
    template<typename T> 
    void fill(const std::vector<T>& a, std::vector<T>& b) {} 
}; 
+1

Дополнительная информация: B является частью иерархии наследования с чистыми виртуальными функциями и завернута в умный указатель на базовый класс. Пользователи должны будут создавать экземпляр B с тем же типом, что и A (что добавляет вероятность ошибки) и не будет очевидным для пользователей классов, поэтому я бы предпочел избежать этого. – pmr

+0

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

4

Templatize fill:

class B { 
public: 
    template<typename T> 
    void fill(const std::vector<T>& a, std::vector<T>& b) 
    { /*...*/ } 
    //... 
}; 

(из описание он видит, что b должен быть const std::vector<T>&.)

2

Вы можете определить B в качестве шаблона класса, заполнить как функция шаблона (внутри нешаблонном класса B), или, мой любимый, используйте стандартный std::transform/std::copy/std::fill, которые уже шаблон функции, чтобы заполнить свой вектор.
(Все находятся внутри заголовка <algorithm>).

+0

Не знал о функциях члена шаблона в классах без шаблонов. Лучший вариант до сих пор с std :: transform. – pmr

5

У вас есть ряд ответов, но я должен не согласиться с ними, по крайней мере, в некоторой степени. Моя немедленная реакция заключается в том, что вы не должны пропускать вектор до b::fill. Скорее, вы должны передать итератор (или, возможно, пару итераторов). Остальное в основном верно, хотя: это все равно означает, что fill должен быть функцией члена шаблона. Когда вы его назовете, вы, вероятно, захотите передать std::back_insert_iterator, обычно полученный с std::back_inserter.

Часть того, что вы сказали, кажется, внутренне противоречивым, хотя: если b::fill изменяет vec1 и vec2, они, вероятно, должны не быть переданы в качестве ссылки на константные. По общему признанию, const не имеет своего обычного значения при применении к контейнеру, но факт остается фактом: передача ссылки на const в функцию, единственное намерение, по-видимому, изменить то, что передано, кажется неправильным.

+1

Согласен Я согласен с тем, что вы должны проходить диапазоны итераторов, а не контейнеры. Он также должен проверить стирание типа итератора. У Томаса Беккера есть класс any_iterator, как и в Публичной библиотеке Adobe. –

+0

О ссылках на const: будет изменен только второй вектор. Об использовании итераторов: операция заполнения будет довольно тяжелой (много вставок), и она может выиграть от vector :: reserve (int). Как я могу получить такое повышение производительности с помощью std :: back_inserter? – pmr

+0

резервные запасы _space_ (а также один из конструкторов). он не создает объект. вы можете использовать reserve() и back_insert. В результате он создает (или присваивает) заранее выделенное пространство, которое именно вы хотите. (и для объектов с тяжелой конструкцией и назначением света вы можете создать вектор с требуемым размером и не использовать back_inserter) –