Переименовать 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::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