user245019
user245019

Reputation:

Change the Type of a Template Class

As an example in Ruby (1.8)

i = 4
i.class => fixnum

i += 1.3
i.class => float

Can this be achieved in C++?

for instance

template<class T>
struct Number {};

Number<int> foo;

foo.changeTypeToFloat(); // <-- Possible?

// foo now Float?

Upvotes: 0

Views: 4909

Answers (5)

Reno
Reno

Reputation: 33792

Nope you cant.

However you can have a very awkward solution involving union / overloading the = operator which i haven't tried out. So i cant say it'll work.

Upvotes: 0

&#201;ric Malenfant
&#201;ric Malenfant

Reputation: 14148

What follows is a direct answer to the question, as asked. As comments on the question suggest, it would be interesting to know why you are asking it, i.e., what you are trying to achieve.

As Oli writes in his answer, C++ is statically typed so no, the type of a variable can't be changed at runtime.

However, if you know in advance the set of types you want for your variable (from your example int and float), you could declare a variable whose type is "int or float". This is the union solution other answers allude to. However, unions have their quirks and are pretty error-prone. Moreover, a union alone is usually not enough, as some information about the currently held type is usually necessary.

There comes Boost.Variant, which is a "discriminated union" (a union which "knows" what type it is currently holding). It allows you to write something like:

// Warning: off the top of my head, not compiled, less tested
boost::variant<int, float> int_or_float;

// Variants initialize by default as the first type in their list,
// so int_or_float is currently holding an int
assert(int_or_float.which() == 0);

int_or_float = 0.1;

// Now holding a float
assert(int_or_float.wich() == 1);

Upvotes: 0

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506905

Like others say, in C++ this can't be done. The issue is not specific to class templates, though. But there are some workarounds that work in some scenarios.


You can use boost::variant<> to do what you want

boost::variant<int, float> v;
v = 0; // v is now storing an int
v = 0.f; // v is now storing a float

struct A { 
  typedef void result_type;
  void operator()(int i) const {
    // process the int
  }
  void operator()(float f) const {
    // process the float
  }
};

// If v stores an int, it calls the int version. 
// Otherwise it calls the float version. 
boost::apply_visitor(A(), v);

See boost::variant.


You can use lexical scoping to make a new variable that hides the name of the other. This is usable when you just want the name to change its meaning, not necessarily the previous object. An important difference is that this changes things at compile time only. boost::variant is able to track its stored type at runtime.

int i = 0; // i now refers to an int variable
{
  float i = 0.f; // i now refers to a float variable
}
// i refers again to an int variable.

Hope it helps.

Upvotes: 3

Chubsdad
Chubsdad

Reputation: 25497

In C++, objects can't change their type at run time.

However, ere is a rough equivalent of a possibility

template<class T> 
struct Number {
   template<class U> operator U(){
      U temp;
      // conversion code typically using casts e.g.
      return temp;
   }
};

This lets you write code such as

template<class T>
struct A{
   template<class U> operator U(){
      return U();
   }
};


int main(){
   A<int> a1;
   float f1 = a1;    // convert a1 to float equivalent and so on.
   A<float> f2 = a1; // convert a1 of type A<int> to A<float>
}

Upvotes: 1

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272467

C++ is a statically-typed language. A variable has a fixed type. The best you can do at the language level is a conversion to a new variable, e.g.:

int i = 5;
float f = static_cast<float>(i);

Alternatively, you could write a variant class, and have the conversion handled internally. But this would really be syntactic sugar for the above.

Upvotes: 5

Related Questions