С++ эквивалент динамического ключевого слова С# 4.0?

В C# 4.0 можно использовать ключевое слово dynamic в качестве заполнителя для типа, который не известен до времени выполнения. Есть определенные крайние случаи, когда это чрезвычайно полезное поведение. Можно ли эмулировать что-то подобное в C++, возможно, используя функции C++0x или RTTI?


person Derek Thurn    schedule 12.11.2010    source источник
comment
Попытка построить DSL типа утки, который компилируется в C++, в основном.   -  person Derek Thurn    schedule 12.11.2010
comment
Так совпало, что я написал об утиной печати на C++. Короче говоря, вы этого не сделаете. Шаблоны дают вам утиную типизацию во время компиляции, но C++ имеет статическую типизацию. Шаблоны и полиморфизм близки, но часто немного уродливы. Похоже, вам нужен Boost.Proto.   -  person GManNickG    schedule 12.11.2010
comment
будет ли ваш DSL поддерживать пользовательские типы?   -  person Tony Delroy    schedule 12.11.2010


Ответы (6)


Не совсем. Самое близкое, что вы можете получить, это 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 */
};
person casablanca    schedule 12.11.2010
comment
Boost.Variant или Boost.Any могут ОЧЕНЬ помочь с такими вещами. - person KitsuneYMG; 12.11.2010

Функция C# dynamic сильно зависит от встроенных в .NET возможностей отражения. Поскольку стандартный C++ не предлагает поддержки отражения, вы никак не сможете добиться аналогичного поведения. RTTI позволит вам безопасно понижать указатели, но это почти все. Вы еще очень далеки от возможности перечислять поля и методы и вызывать их динамически.

person Trillian    schedule 12.11.2010

Как уже говорили другие, в общем случае это невозможно, но я думаю, было бы информативно понять, почему нет.

У проблемы есть два уровня: синтаксический уровень и семантический уровень.

На синтаксическом уровне у вас есть следующий код:

dynamic d = /* something */;
d.Foo(bar); // Foo is unknown at compile time

В .NET dynamic — это функция компилятора, которая вместо создания вызова функции создает сайт вызова, который содержит имя функции и типы параметров (для перегрузки ). Это означает, что если вы хотите поддерживать динамическую обработку, вам нужно изменить компилятор. Это правда, что метапрограммирование шаблонов позволяет делать подобные вещи, но TMP по своей природе выполняется во время компиляции и, следовательно, не подходит для поддержки вызова во время выполнения.

Если вы не разбираетесь в синтаксисе, вы можете поддержать что-то вроде этого:

dynamic d = /* something */;
d.invoke("Foo", bar);

На семантическом уровне Как @Trillian (кстати, классное имя пользователя) сказал, что динамическая обработка зависит от отражения, это не совсем верно, вы можете указать, как dynamic реализован, и по умолчанию для типов CLR используется отражение, поэтому тип, связанный с переменной dynamic, должен поддерживать какой-либо вид проверки во время выполнения (например, IDispatch COM). Это неверно для общего случая в C++, но если вы можете сузить свою поддержку только до типов, которые поддерживают (известный) тип проверки, вы можете реализовать dynamic в C++ (без синтаксиса, как указано выше).

person Motti    schedule 13.11.2010

Это невозможно. Размеры объектов должны быть известны во время компиляции, чтобы указатель стека мог перемещаться на соответствующее количество байтов. Если вы не объявите тип, компилятор не будет знать размер. C# решает эту проблему, делая все объекты указателями.

person jhourback    schedule 12.11.2010

Этот пример на 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
person Jim Fell    schedule 25.02.2020

Я не могу придумать возможный путь кода, где тип значения фактически неизвестен до момента выполнения. Даже если вы связываете два модуля вместе (динамически, во время выполнения), оба уже скомпилированы, и типы, которые они могут возвращать, также полностью определены и фактически закодированы в искаженных именах символов, предоставляемых библиотекой.

Однако вы можете отложить знание типов до тех пор, пока код не будет фактически скомпилирован. В C++0x есть ключевое слово auto, которое обеспечивает вывод типа из выражения, используемого для инициализации переменной, а в текущем C++ вы можете использовать шаблоны, например:

template<typename T>
T square(const T& someArg){
   return T*T;
}

Изменить: исходя из вашего комментария к вашему вопросу, у вас, вероятно, нет ситуации, когда тип неизвестен. Более вероятно, что тип ограничен одним из нескольких (предопределенных) типов. для этого вы можете использовать тип union, предпочтительно используя boost::variant

person SingleNegationElimination    schedule 12.11.2010