FrozenKiwi
FrozenKiwi

Reputation: 1513

Is it possible to force a new template instantiation?

I want to have something like the following (psuedo-C++) class. The basic idea is any new value will be initialized to the last set value.

StickyData.hpp

template<typename T>
class StickyData {
  static T s_lastValue;
  T m_value;
  StickyData() { m_value = s_lastValue; } // Initialize to last set value
  T& operator = (T& rhs)  { 
       m_value = s_lastValue = rhs;
  }
}

template<> StickyData<T>::s_lastValue;

UseData.cpp

typedef int Ford;
typedef int GM;
typedef int Toyota;

StickyData<Ford> aFord;
StickyData<GM> aGM;
StickyData<Toyota> aToyota;

aFord = 10;
aGM = 2
aToyota = 20;

StickyData<Ford> anotherFord; // I want this automatically initialized to 10

For this to work, I need unique compilations of StickyData for each of these typedef's. I actually thought this would work as-is, but it appears when I run this code that I only have 1 static int created for all these different template instantiations.

Can I force a new template compilation somehow for the same underlying value type?

Upvotes: 0

Views: 176

Answers (1)

Bill Lynch
Bill Lynch

Reputation: 81916

In your example code, Fords, GMs and Toyotas are all the same type. You should declare them as actual separate types:

struct Toyota {};
struct Ford   {};
struct GM     {};

Currently, your code is equilvient to:

HoldData<int> aFord;
HoldData<int> aGM;
HoldData<int> aToyota;

Here's a full implementation of what I'm suggesting above:

#include <iostream>

template<typename Hash, typename Value>
struct StickyData {
        static Value s_lastValue;
        Value m_value;
        StickyData(): m_value(s_lastValue) {}

        StickyData<Hash, Value> & operator=(Value const & rhs) {
                m_value = s_lastValue = rhs;
                return *this;
        }
};

struct GM {};
struct Ford {};
struct Honda {};

template <typename Hash, typename Value> Value StickyData<Hash, Value>::s_lastValue = 0;

int main() {
        StickyData<GM, int> aGM;
        StickyData<Ford, int> aFord;
        StickyData<Honda, double> aHonda;

        aGM = 3;
        aFord = 4;
        aHonda = 7.89;

        std::cout << "aGM:    " << aGM.m_value << "\n";
        std::cout << "aFord:  " << aFord.m_value << "\n";
        std::cout << "aHonda: " << aHonda.m_value << "\n";
        std::cout << "\n";

        StickyData<GM, int> aNewGM;
        std::cout << "aNewGM: " << aGM.m_value << "\n";
}

Which will output:

aGM:    3
aFord:  4
aHonda: 7.89

aNewGM: 3

In response to the comment: "... But the compiler does know the difference, for example, if you have typedef'ed argument, you can mark something explicit which will then not accept a type 'int' as an argument ...".

I have the following code:

typedef int foo;

class C {
    explicit C(int x);
    explicit C(foo x);
};

This code fails to compile with the following error:

blah.cc:5:11: error: ‘C::C(foo)’ cannot be overloaded
  explicit C(foo x);
           ^
blah.cc:4:11: error: with ‘C::C(int)’
  explicit C(int x);
           ^

Upvotes: 2

Related Questions