简体   繁体   中英

runtime determine type for C++

I am wondering if type can be determined as runtime information in C++.

(1) Although my question is quite general, for simplicity, I will start from a simple example:

 #include <stdio.h>  
 #include <iostream>  
 #include <cstring>  
 using namespace std;  
 int main(int argc, char * argv[])  
 {  
 if (strcmp(argv[1], "int")==0)   
 {  
     int t = 2;   
 }else if (strcmp(argv[1], "float")==0)  
 {  
     float t = 2.2; 
 } 
 cout << t << endl;  // error: ‘t’ was not declared in this scope
 return 0;  
 }

For this example, there are two questions:

(a) "argv[1] to t" is wrong, but can the type info in the C string argv[1] be converted to the actual type keyword? So we don't need to check for every type by if-else clause and strcmp.

(b) how to make variable t defined inside the local scope of the if clause still valid outside. ie how to "export" a local variable to the outside of its scope?

(2) Generally speaking, not specific to the simple example above, what are the usual ways to runtime determine types? It seems to me that there might be some ways:

(a) one can put the processing of the variable defined from the type inside the same scope its definition. eg

 #include <stdio.h>  
 #include <iostream>  
 #include <cstring>  
 using namespace std;  
 int main(int argc, char * argv[])  
 {  
 if (strcmp(argv[1], "int")==0)   
 {  
     int t = 2;   
     cout << t << endl; 
 }else if (strcmp(argv[1], "float")==0)  
 {  
     float t = 2.2; 
     cout << t << endl; 
 } 
 return 0;  
 }

And possibly use template function to make the common code for various types reusable.

(b) or one may use abstract class type and polymorphism to indirectly export the definition out, but I am not sure how exactly.

Thanks for your advice!

1a: No, types are not objects or values in C++ (as they are, for example, in Python). You can, however, use various values selected by the value of argv[1].

1b: Sorry, just can't do that.

2: dynamic_cast and typeid (both operators) are the only tools currently provided by the language to query type (not unusual, most languages have very few, but dedicated, tools for that), and using them solely to query type is often discouraged depending on situation (also not unusual among other languages).

2a: Yes, and as that is the simple, obvious, and works here—there's no reason to use anything else, but as it's example code, let's assume you need a different solution. You could call a function template instantiated on the right type, but as this is pretty much the same thing as the rest of 2a, I don't go into it.

2b: Example using a subclass template, just because it's handy:

struct Base {
  virtual ~Base() {}
  friend std::ostream& operator<<(std::ostream& s, Base const& v) {
    v._print(s);
    return s;
  }
private:
  virtual void _print(std::ostream&) const = 0;
};

template<class T>
struct Value : Base {
  T data;
  explicit
  Value(T const& data) : data(data) {}
private:
  virtual void _print(std::ostream& s) const {
    s << data;
  }
};

Use:

int main(int argc, char** argv) {
  using namespace std;
  auto_ptr<Base> p;
  string const type = argc > 1 ? argv[1] : "int";
  if (type == "int") {
    p.reset(new Value<int>(2));
  }
  else if (type == "float") {
    p.reset(new Value<double>(2.2));
  }
  cout << *p << '\n';
  return 0;
}

This is starting to merge the two types into one type, and they both present the same interface, Base, here. However, this doesn't lend itself well to every solution, and a variant such as boost.variant can be better, particularly when the various types required are small in number and known well in advance.

You need a class that's capable of storing a value of different types. Short from a union, Boost's variant class would be the proper choice.

查看Boost.Variant

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM