Я задаюсь вопросом, может ли тип быть определен как информация о выполнении в C++.
(1) Хотя мой вопрос является довольно общим для простоты, я запущу с простого примера:
#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;
}
Для этого примера существует два вопроса:
(a) "argv[1] к t" является неправильным, но может информация о типе в струне до argv [1] быть преобразованной в фактическое ключевое слово типа? Таким образом, мы не должны проверять на каждый тип если-выражением-else и strcmp.
(b) как сделать переменную t определенной в локальном объеме выражения if все еще допустимый снаружи. т.е. как "экспортировать" локальную переменную в за пределами ее объема?
(2) Вообще говоря, не характерный для простого примера выше, что обычные пути ко времени выполнения, определяют типы? Мне кажется, что могли бы быть некоторые пути:
(a) можно поместить обработку переменной, определенной от типа в том же объеме его определение. например.
#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;
}
И возможно используйте шаблонную функцию для создания общего кода для различных типов допускающим повторное использование.
(b) или можно использовать тип абстрактного класса и полиморфизм для косвенного экспорта определения, но я не уверен как точно.
Спасибо за Ваш совет!
1a: Нет, типы не являются объектами или значениями в C++ (как, например, в Python). Однако можно использовать различные значения, выбираемые значением argv[1].
1b: К сожалению, просто так нельзя.
2: dynamic_cast и typeid (оба оператора) в настоящее время являются единственными инструментами, предоставляемыми языком для запроса типа (не редкость, в большинстве языков для этого есть очень мало, но выделенных инструментов), и использование их исключительно для запроса типа часто не поощряется в зависимости от ситуации (также не редкость среди других языков).
2a: Да, и так как это просто, очевидно, и работает здесь - нет причин использовать что-либо другое, но как пример кода, предположим, что вам нужно другое решение. Можно вызвать шаблон функции, инстанцированный на правильный тип, но так как это практически то же самое, что и остальные 2a, я в него не вдаюсь.
2b: Пример использования шаблона подкласса, просто потому что это удобно:
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;
}
Это начинает объединять два типа в один тип, и оба они представляют один и тот же интерфейс, Базовый, здесь. Однако, это не подходит для каждого решения, и такой вариант, как boost.variant может быть лучше, особенно, когда требуемые различные типы малочисленны и известны заранее.
Вам нужен класс, который способен хранить значения различных типов. Коротко от объединения, будет правильным выбором вариант класса Boost.
.