Преименуване на std::vector в друг клас за претоварване?

Вижте този код.

#include <vector>

template<class ...Args>
using other_vector = std::vector<Args...>;

template<class T>
void f(std::vector<T>& ) {}
template<class T>
void f(other_vector<T>& ) {}

int main()
{
    other_vector<int> b;
    f(b);
    return 0;
}

Не се компилира, защото f се предекларира. Напълно разбирам грешката. Въпреки това имам нужда от втори клас, който се държи като std::vector<T>, но ще се разглежда като различен тип, така че претоварването, както в горния пример, ще бъде законно.

Какво бих могъл да направя?

  • Нека новият клас има std::vector<T> като базов клас. Това може да работи, но човек не трябва да наследява от std контейнери.
  • Нека новият клас има член от тип std::vector и след това предекларирайте всички функции, за да пренасочите към функциите на члена. Звучи като много работа.

Някаква по-добра алтернатива? Разрешени са C++11 или C++14.


person Johannes    schedule 07.01.2014    source източник
comment
Разгледайте BOOST_STRONG_TYPEDEF. Ако не работи с шаблони, вероятно бихте могли да почерпите вдъхновение да направите нещо, което работи.   -  person chris    schedule 07.01.2014
comment
Сигурни ли сте, че имате нужда от две функции за почти един и същи тип?   -  person StoryTeller - Unslander Monica    schedule 07.01.2014
comment
Можете ли да кажете защо ви трябва? Защо не използвате struct vector_wrapper{ std::vector<T> vector; };?   -  person zch    schedule 07.01.2014
comment
@StoryTeller Да, защо не?   -  person Johannes    schedule 07.01.2014
comment
Наследяването от стандартни контейнери е добре (макар и необичайно използвано добре), стига да знаете какво да не правите. Липсата на виртуален деструктор вреди, но само ако разрешите/изисквате поведението на такъв.   -  person chris    schedule 07.01.2014
comment
@zch В някои случаи може да не искам претоварване, но нека да се държат подобно. Тогава би било неудобно. Разбира се, може да се напише претоварване, което просто извиква същата функция за члена на обвивката, но се надявам, че има по-лесно решение.   -  person Johannes    schedule 07.01.2014
comment
Това трябва да се оправдаеш, приятелю. Не бих препоръчал да правите неща, защото защо не!?   -  person StoryTeller - Unslander Monica    schedule 07.01.2014
comment
@StoryTeller Np, просто ме интересува дали работи. Може би си прав, не е необходимо, но мисля, че е интересно и може да подобри моя код.   -  person Johannes    schedule 07.01.2014


Отговори (3)


Може да опитате да се забъркате с разпределителя:

template<class T>
struct allocator_wrapper : T { using T::T; };

template<class T, class A = std::allocator<T>>
using other_vector = std::vector<T, allocator_wrapper<A>>;

Пример на живо

person Daniel Frey    schedule 07.01.2014
comment
using T::T; Уау О.О +1 - person StoryTeller - Unslander Monica; 07.01.2014
comment
@Johannes И в случай, че имате нужда от повече от тези отделни типове, просто добавете целочислен параметър към allocator_wrapper и можете да имате произволен брой от тях... :) - person Daniel Frey; 07.01.2014
comment
@DanielFrey Брилянтна идея, +1 за вашия коментар и вашия отговор - person Glenn Teitelbaum; 07.01.2014
comment
защо не просто: template‹class T, class A = std::allocator‹T›› struct other_vector : std::vector‹T, A› { using std::vector‹T, A›::vector; }; ? - person kiba; 08.01.2014
comment
@kiba Понякога се нуждаете от самия клас да бъде std::vector, а не просто нещо, получено от него, ето пример, който показва, че разликата е забележима, вероятно няма много случаи на употреба, при които бихте направили това, но те съществуват. - person Daniel Frey; 08.01.2014

Ако имате нужда от повече от едно копие, можете да го направите шаблон и да вземете int шаблонен аргумент за "номер на клонинг"

person Community    schedule 07.01.2014
comment
Но все пак ще трябва да използвам една от двете точки, които споменах по-горе, със споменатите недостатъци? - person Johannes; 07.01.2014
comment
@Johannes вярно, но можете да комбинирате параметъра на шаблона int с каквото и решение да имате за 1 клонинг, за да го разширите до N - person Glenn Teitelbaum; 07.01.2014

Можете да опаковате вашия тип, както следва:

// N allow to have several 'version' of the same type T
template <typename T, int N = 0>
class WrapperType
{
public:
    WrapperType() = default;
    WrapperType(const WrapperType&) = default;
    WrapperType(WrapperType&&) = default;

    template <typename ... Ts>
    explicit WrapperType(Ts&& ... ts) : t(std::forward<Ts>(ts)...) {}

    // implicit conversion
    // you may prefer make them explicit or use name get().
    operator const T& () const { return t; }
    operator T& () { return t; }

private:
    T t;
};

И така за вашия случай:

template<class T>
using other_vector = WrapperType<std::vector<T>>;
person Jarod42    schedule 07.01.2014