4

I would like a class to have a function with a template argument, and based on that template argument a particular member variable is manipulated.

For example, if function template specialization were allowed, then something like this:

struct A
{
    struct M1 {};
    struct M2 {};

    // Function template specialization not allowed :(
    template<typename M>
    void addM(M const &m);

    template<>
    void addM(M1 const &m)
    {
        m1_vec_.push_back(m);
    }

    template<>
    void addM(M2 const &m)
    {
        m2_vec_.push_back(m);
    }

    std::vector<M1> m1_vec_;
    std::vector<M2> m2_vec_;
};

Any ideas? I feel like I'm missing something simple but can't quite put my finger on it.

user5406764
  • 1,627
  • 2
  • 16
  • 23
  • 2
    Why not have overloaded functions that take `M1` and `M2`? – Anon Mail Dec 11 '15 at 16:40
  • C++ makes it easy to miss the wood from the trees. ;-) – 5gon12eder Dec 11 '15 at 16:41
  • 1
    On a side note, function templates **can** be specialized (fully). The reason why this code fails is because they can not be specialized within class scope. – SergeyA Dec 11 '15 at 16:48
  • While overloading is (most of the time) the way to go in such scenario, one case where template looks like a better solution is when overloads use exactly the same code, the only difference being the member used. That's not a big deal with a one-line method, but is more of a hassle to duplicate all the code in a more complex one. – void_ptr Dec 11 '15 at 16:53
  • @SergeyA The above code compiles in VS2013. I think the code is valid, struct itself is not a template. – prazuber Dec 11 '15 at 17:12
  • @prazuber, well-known MSVC bug (which they prefer to call an extension). – SergeyA Dec 11 '15 at 17:14

1 Answers1

10

Just overload them :

struct A
{
    struct M1 {};
    struct M2 {};

    void addM(M1 const &m)
    {
        m1_vec_.push_back(m);
    }

    void addM(M2 const &m)
    {
        m2_vec_.push_back(m);
    }

    std::vector<M1> m1_vec_;
    std::vector<M2> m2_vec_;
};

If you do not wish to duplicate addM's code, you can just abstract the vector choice behind another function :

struct A
{
    struct M1 {};
    struct M2 {};

    template <class T>
    void addM(T const &m)
    {
        getVec<T>().push_back(m);
    }

    std::vector<M1> m1_vec_;
    std::vector<M2> m2_vec_;

private:
    template<class T>
    std::vector<T> &getVec();
};

template <>
std::vector<A::M1> &A::getVec() { return m1_vec_; }

template <>
std::vector<A::M2> &A::getVec() { return m2_vec_; }
Quentin
  • 62,093
  • 7
  • 131
  • 191
  • The second answer is totally what I was looking for. No matter how good I get at C++, it always amazes me how much better some people are. Thx for the help! – user5406764 Dec 11 '15 at 17:26