6

Look at this code.

#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;
}

It does not compile, because f is being redeclared. I totally understand the error. However, I need a second class that behaves like std::vector<T>, but will be seen as a different type, so that overloading, like in the above example, would be legal.

What could I do?

  • Let the new class have std::vector<T> as a base class. This might work, but one should not inherit from std containers.
  • Let the new class have a member of type std::vector and then redeclare all functions to redirect to the functions of the member. Sounds like a lot of work.

Any better alternative? C++11 or C++14 allowed.

Johannes
  • 2,901
  • 5
  • 30
  • 50
  • 6
    Have a look at `BOOST_STRONG_TYPEDEF`. If it doesn't work with templates, you could probably draw inspiration to make something that does. – chris Jan 07 '14 at 14:01
  • 1
    Are you sure you need two functions for pretty much the same type? – StoryTeller - Unslander Monica Jan 07 '14 at 14:02
  • 1
    Can you tell why do you need it? Why not use `struct vector_wrapper{ std::vector vector; };`? – zch Jan 07 '14 at 14:04
  • @StoryTeller Yes, why not? – Johannes Jan 07 '14 at 14:04
  • 2
    Inheriting from standard containers is ok (albeit uncommonly used well) as long as you know what not to do. The lack of virtual destructor hurts, but only if you allow/require the behaviour of one. – chris Jan 07 '14 at 14:06
  • @zch In some cases, I might not want an overload, but let them behave similar. Then it would be uncomfortable. Of course, one could write an overload which just calls the same function for the wrapper's member, but I hope there is an easier solution. – Johannes Jan 07 '14 at 14:07
  • That's for you to justify, mate. I wouldn't recommend doing stuff because "why not!?" – StoryTeller - Unslander Monica Jan 07 '14 at 14:08
  • @StoryTeller Np, I am just interested if it works. Maybe you're right, it is not necessary, but I think it's interesting and can improve my code. – Johannes Jan 07 '14 at 14:13

3 Answers3

18

You might try to mess with the allocator:

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>>;

Live example

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • `using T::T;` Whoa O.O +1 – StoryTeller - Unslander Monica Jan 07 '14 at 14:11
  • 1
    @Johannes And in case you need more of those distinct types, just add an integer parameter to the `allocator_wrapper` and you can have any number of them... :) – Daniel Frey Jan 07 '14 at 16:01
  • @DanielFrey Brilliant idea, +1 for your comment and your answer – Glenn Teitelbaum Jan 07 '14 at 19:21
  • why not simply: template> struct other_vector : std::vector { using std::vector::vector; }; ? – kiba Jan 08 '14 at 13:00
  • @kiba You sometimes need the class itself to be a `std::vector` and not just something derived from it, [here's an example](http://coliru.stacked-crooked.com/a/eb92fd04e809a82f) which shows that the difference is detectable, there are probably not many use-cases where you'd do this but they do exist. – Daniel Frey Jan 08 '14 at 17:01
0

If you need more than one copy, you can make it a template and take an int template arg for "clone number"

Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80
0

You may wrap your type as follow:

// 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;
};

And so for your case:

template<class T>
using other_vector = WrapperType<std::vector<T>>;
Jarod42
  • 203,559
  • 14
  • 181
  • 302