C++ эквивалент "динамического" ключевого слова C# 4.0?
В C# 4.0 вы можете использовать ключевое слово "dynamic" в качестве заполнителя для типа, который не известен до времени выполнения. Есть определенные случаи, когда это чрезвычайно полезное поведение. Можно ли эмулировать что-то подобное в C++, возможно, используя функции C++0x или RTTI?
5 ответов
На самом деле, нет. Самое близкое, что вы можете получить, это void *
, но вам все равно нужно привести его к соответствующему типу, прежде чем вы сможете его использовать.
Обновить:
Попытка построить DSL типа утки, который компилируется в C++, в основном.
Вы можете сделать это по крайней мере двумя способами:
Союзный вариант
struct MyType {
enum { NUMBER, STRING /* etc */ } type;
union {
double number;
string str;
};
};
Полиморфный класс, иерархия
class MyType {
public:
/* define pure virtual operations common to all types */
};
class MyNumber : public MyType {
private:
double number;
public:
/* implement operations for this type */
};
C#'s dynamic
Эта функция сильно зависит от встроенных возможностей отражения.NET. Поскольку стандартный C++ предлагает почти без поддержки рефлексии, вы не можете получить подобное поведение. RTTI позволит вам безопасно понижать указатели, но это почти все. Вам еще далеко до возможности перечислять поля и методы и вызывать их динамически.
Как уже говорили другие, в общем случае это невозможно, но я думаю, что было бы полезно узнать, почему нет.
Существует два уровня проблемы: синтаксический уровень и семантический уровень.
На уровне синтаксиса у вас есть следующий код:
dynamic d = /* something */;
d.Foo(bar); // Foo is unknown at compile time
В.NET dynamic
это функция компилятора, которая вместо генерации вызова функции создает сайт вызова, который содержит имя функции и типы параметров (для перегрузки). Это означает, что если вы хотите поддерживать динамический, вы должны изменить компилятор. Это правда, что шаблонное метапрограммирование позволяет делать подобные вещи, но TMP по своей природе выполняется во время компиляции и, следовательно, не справится с задачей поддержки вызова во время выполнения.
Если вы не разбираетесь в синтаксисе, вы можете поддерживать что-то вроде этого:
dynamic d = /* something */;
d.invoke("Foo", bar);
На семантическом уровне Как сказал @Trillian (крутое имя пользователя BTW), динамическое зависит от рефлексии, это не совсем верно, вы можете указать, как dynamic
реализован, и типом по умолчанию для типов CLR является отражение, поэтому тип, который связан с dynamic
переменная должна поддерживать какую-то проверку времени выполнения (например, COM IDispatch
). Это не верно для общего случая в C++, но если вы можете сузить свою поддержку только до типов, которые поддерживают (известный) тип проверки, которую вы можете реализовать dynamic
в C++ (без синтаксиса, как указано выше).
Этот пример на github предоставляет одну возможную реализацию в зависимости от сложности вашей функции.
template <typename X, typename Y>
auto add(X x, Y y) -> decltype(x + y) {
return x + y;
}
add(1, 2); // == 3
add(1, 2.0); // == 3.0
add(1.5, 1.5); // == 3.0
Это невозможно. Размеры объекта должны быть известны во время компиляции, поэтому указатель стека может перемещаться на соответствующее число байтов. Если вы не объявите тип, то компилятор не будет знать размер. C# обходит эту проблему, делая все объекты указателями.
Я не могу придумать возможный путь кода, где тип значения фактически неизвестен вплоть до времени выполнения. Даже если вы связываете два модуля вместе (динамически, во время выполнения), оба они уже скомпилированы, и типы, которые они могут возвращать, также полностью определены и фактически закодированы в искаженные имена символов, которые предоставляет библиотека.
Однако вы можете отложить знание типов до тех пор, пока код не будет фактически скомпилирован. В C++0x есть auto
Ключевое слово, которое обеспечивает вывод типа из выражения, использованного для инициализации переменной, и в текущем C++ вы можете использовать шаблоны, например так:
template<typename T>
T square(const T& someArg){
return T*T;
}
Редактировать: основываясь на вашем комментарии к вашему вопросу, у вас, вероятно, нет ситуации, когда тип неизвестен. Более вероятно, что тип ограничен одним из нескольких (предопределенных) типов. для этого вы можете использовать union
тип, предпочтительно с использованием boost::variant