Отражение в известном наборе классов - PullRequest
0 голосов
/ 25 февраля 2012

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

Доступно несколько классов (25+), и количество строительных блоков увеличивается.Если я буду искать каждый тип в каждом другом типе, то у нас будет значительно большее количество возможных комбинаций.

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

Можно ли узнать, присутствует ли переменная функции / члена в определенном типе во время выполнения.

Мой пример кода показан ниже:

#include <iostream>

struct Generic {};

struct SimpleType {int toString(){return 0;}};

enum ETypeVal{eVal1 = 0, eVal2 = 1, eVal3 = 2};


template <typename ETypeVal val>
struct Hello
{
    int toString(){return 0;}
};

template <> struct Hello<eVal2>
{
    int toString(){return 1;}
};

template <> struct Hello<eVal3>
{   
};


template <class Type>
class TypeHasToString
{
public:
    typedef bool Yes;
    typedef short No;

    static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));

private:

    template <typename T, T> struct TypeCheck;

    template <typename T> struct ToString
    {
        typedef int (T::*fptr)();
    };

    template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
    template <typename T> static No  HasToString(...);
};

int main(int argc, char *argv[])
{
    // all this works fine
    std::cout << TypeHasToString<Generic>::value << std::endl;
    std::cout << TypeHasToString<SimpleType>::value << std::endl;
    std::cout << TypeHasToString<Hello<eVal1>>::value << std::endl;
    std::cout << TypeHasToString<Hello<eVal2>>::value << std::endl;
    std::cout << TypeHasToString<Hello<eVal3>>::value << std::endl;

    // Unable to deduce for type that are not known at compile time
    // Is it possible to remove this limitation ?
    for(int val = eVal1; val <= eVal3; val++)
    {
        std::cout << TypeHasToString< Hello< (ETypeVal)val > >::value << std::endl;
    }

    return 0;
}

Ответы [ 4 ]

1 голос
/ 25 февраля 2012

Я использовал boost :: mpl для выполнения итерации и печати значений.Большая часть этого должна быть возможна без каких-либо из них, но я настоятельно рекомендую использовать его.Также я исправил некоторые вещи в вашем коде.Возможно, вы также захотите использовать BOOST_HAS_XXX вместо домашнего решения (ваш стиль SFINAE довольно неудобен).

1 голос
/ 25 февраля 2012

У нас нет отражения во время выполнения в C ++. Но у нас есть разные вещи, которые большинству программистов на C ++ нравятся лучше, чем рефлексия; -).

Если я понимаю ваш вопрос, вам нужно создать браузер объектов, и вы знаете все типы объектов. Под «вы знаете все типы ваших объектов» я имею в виду «вы не получите объект как нечто на другом конце указателя из dll, который вы не кодировали».

Итак, может быть, вы можете использовать boost :: fusion ? Указанная библиотека предназначена для итерации по агрегатам и, в то же время, для извлечения обоих типов данных и для каждого элемента агрегата. Это как итераторы над членами структуры, если я должен выразить это в изящном виде. Конечно, вы можете использовать с вашими пользовательскими типами.

1 голос
/ 25 февраля 2012

Вы не можете знать во время выполнения, если вы не знаете во время компиляции. У вас есть код, который нужно знать во время компиляции для одной функции. Вы можете просто сделать из него макрос, чтобы иметь его для любой функции, которую вы хотите проверить. (Отказ от ответственности за макрос: в этом случае макросы хороши, вот как работает BOOST_MPL_HAS_XXX_TEMPLATE_DEF).

В качестве альтернативы есть boost :: fusion , как упомянуто dsign. Но я предпочитаю другой: boost :: рефлекс (не на самом деле в boost подробнее здесь ). Синтаксис макроса проще (вам не нужно указывать тип в макросе), а код очень легкий. Кроме того, есть полная функция boost :: mirror ( скачать здесь ), еще не реализованная в boost, которая гораздо более полная и даже имеет генератор кода для создания вызовов макросов. отражение времени выполнения в стиле Java.

0 голосов
/ 25 февраля 2012

Я думаю, что в этом случае вам нужен полиморфизм времени выполнения. Используйте интерфейсы вместо шаблонов для такого рода проблем. Интерфейсы дадут знание о методах в вашем объекте, но ничего не скажут о переменных-членах. Таким образом, в стандарте c ++ нет доступных отражений (единственное, что предоставляет c ++, это оператор type_info, который может помочь вам в некоторых случаях), вы можете попытаться найти некоторые расширения для вашего компилятора, которые предоставят вам возможности отражения.

...