1

I have a class for which I'd like an estimation of how much memory it's consuming:

template <typename T, typename U>
class MyTemplateClass
{
    size_t EstimateMemoryConsumption() const
    {
        // the memory consumption is a function of the size of the first template argument
        return f(sizeof(T));
    }
}

And this works fine. Recently I've been asked to support T == std::string. The current implementation doesn't work because sizeof(std::string) doesn't reflect the memory consumption of an std::string (I need to call capacity() on the std::string). According to this, I cannot give a partial specialization for the member function (for T == std::string, and any U)

Is there a different way to achieve this?

Community
  • 1
  • 1
Shmoopy
  • 5,334
  • 4
  • 36
  • 72
  • 1
    Refactor a base class with one template parameter, and then derive from this class. – Olaf Dietsche Apr 25 '17 at 10:12
  • you cannot do it generically, what about `std::vector`? for every solution you'll find, you can always wrap it in another container class, breaking your solution. – David Haim Apr 25 '17 at 10:31
  • It's not clear from your question whether there is a single T data member, or a container of T, or anything else. Can you add more details on what f is and in where the type T is used in the data? – Nir Friedman Apr 25 '17 at 10:44

2 Answers2

2

You could make memory consumption a function of the template parameter itself.

template <typename T, typename U>
class MyTemplateClass
{
    size_t EstimateMemoryConsumption() const
    {
        return estimate<T>(my_data_member);
    }
};

template <typename T>
size_t estimate(const T&) noexcept { return sizeof(T); }

template <>
size_t estimate<std::string>(const std::string& x) noexcept 
{ 
    return x.capacity(); 
}
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • This answer is all good and well assuming there is just a single member of type T, but I'm not sure that's the case. – Nir Friedman Apr 25 '17 at 10:44
1

Use traits to achieve specialization:

template <typename T>
class MyTemplateClassTraits
{
public:
    static size_t EstimateMemoryConsumption(T& member)
    {
        return 0; // implement...
    }
};

template <>
class MyTemplateClassTraits<std::string>
{
public:
    static size_t EstimateMemoryConsumption(std::string& member)
    {
        return 0;  // implement...
    }
};

Without changing your current API:

template <typename T, typename U>
class MyTemplateClass
{
    //...

    size_t EstimateMemoryConsumption() const
    {
        // the memory consumption is a function of the size of the first template argument
        return MyTemplateClassTraits<T>::EstimateMemoryConsumption(t_data_member);
    }

    //...
}
keith
  • 5,122
  • 3
  • 21
  • 50