c++templatesspecialization

How to make a templated class to call different methods, depending on type


I have a storage class, which can store either primitive types, like double and more complicated types, along the lines of SelectiveAccumulator class below. For example, increasing value of an element can be either a simple addition or more involved action. I would like to avoid overloading operator+= and use partial specialization or overloading instead? Is it at all possible?

#include <iostream>
#include <vector>

/**
 * Class, which accumulates values only if increment is above a certain
 * threshold.
 */
template <class X>
class SelectiveAccumulator
{
  public:
    typedef X value_type;
    /**
     * Constructor -- sets the lower threshold and initializes accumulated value.
     * @param t threshold
     * @param init initial value (usually 0)
     */
     SelectiveAccumulator(const X& t, const X& init) :
       threshold(t),
       accumulated_value(init)
     {}
     
     /**
      * Increases accumulated value by 'increment' if it is larger than
      * threshold. Otherwise does nothing.
      * @param increment increase the accumulated value by.
      */
     void Inc(const value_type& increment)
     {
         if (increment > threshold) 
           accumulated_value += increment;
     }
     
     ///Returns accumulated value.
     X Value() const { return accumulated_value; }
  private:
    const X threshold; 
    X accumulated_value;       //accumulated value
};

template <class T>
class Storage
{
  public:
    typedef T value_type;

    /**
     * Constructor, allocated memory for storage vector.
     * @param n size of vector
     * @param initial values to put into storage.
    */
    Storage(const std::size_t n, const T& init_value) :
      storage(n, init_value)
    {}
    
    /**
     * Increases value of element with the given index for classes, supporting
     * += operator. For simplicity do not check for range.
     * @param index index of the element in storage to increase.
     * @param v value to increase the element by.
     */
    void IncreaseValue(std::size_t index, const T& v)
    {
        storage[index] += v;
    }
    
    const T& Get(std::size_t index)
    {
        return storage[index];
    }
    
    /**
     * Miraculously overloaded / specialized method, so I can increase value of
     * element with the given index for SelectiveAccumulator type.
     * @param index index of the element in storage to increase.
     * @param v value to increase the element by.
     */
    template <class SelectiveAccumulator > 
    void IncreaseValue(std::size_t index, 
           const typename SelectiveAccumulator::value_type & v)
    {
        storage[index].Inc(v);
    }

  private:
    std::vector<T> storage;
};

///Take the Storage type class and increase the third element. Should work for 
/// typename S::value_type double and SelectiveAccumulator.
template <class S, class T>
void Increase3rdElement(S& storage, const T& increment)
{
    storage.IncreaseValue(3, increment);
}

int main() 
{
    Storage<double> s1(10, 0.0);
    Increase3rdElement(s1, 0.9);
    std::cout << "s1[3] = " << s1.Get(3) << std::endl;

    Storage<SelectiveAccumulator<double> > s2(10, {1.0, 0.0});
    //How to make this work?
    //Increase3rdElement(s2, 0.9);
    //std::cout << "s2[3] = " << s2.Get(3).Value << std::endl;
    //std::cout 
    return 0;
}

Source code


Solution

  • In

    template <class SelectiveAccumulator > 
    void IncreaseValue(std::size_t index, 
           const typename SelectiveAccumulator::value_type & v)
    {
        storage[index].Inc(v);
    }
    

    SelectiveAccumulator is non deducible... but it should just be T:

    template <class SelectiveAccumulator = T> 
    void IncreaseValue(std::size_t index, 
           const typename SelectiveAccumulator::value_type & v)
    {
        storage[index].Inc(v);
    }
    

    Demo