2013-05-17 9 views
0

У меня есть класс, который имеет шаблон:Функция вызова на boost :: variant независимо от типа?

template<class T = int> class slider; 

Класс имеет метод void Process(void), поэтому, я думаю, что это должно быть отозвано regarless типа, возвращаемое значение является недействительным, и нет никаких параметров к нему.

А теперь у меня есть этот код для вызова процесса каждый кадр в моем приложении:

//class menu: 
typedef boost::variant<std::shared_ptr<slider<int>>,std::shared_ptr<slider<float>>,std::shared_ptr<slider<double>>,std::shared_ptr<slider<char>>> slider_type; 
std::map<std::string,slider_type> Sliders; 
//buttons ... etc ... 
void Process() 
{ 
    if(!Sliders.empty()) 
    { 
     for(auto i = Sliders.begin(); i != Sliders.end(); ++i) 
     { 
      switch(i->second.which()) 
      { 
       case 0://slider<int> 
       { 
        boost::get<std::shared_ptr<slider<int>>>(i->second)->Process(); 
        break; 
       } 
       case 1://slider<float> 
       { 
        boost::get<std::shared_ptr<slider<float>>>(i->second)->Process(); 
        break; 
       } 
       //..... 
      } 
     } 
    } 
} 

Можно ли выполнить процесс функции(), как показано в следующем примере?

for(auto i = Sliders.begin(); i != Sliders.end(); ++i) 
    { 
     switch(i->second.which()) 
     { 
      boost::get<???Any???>(i->second)->Process(); 
     } 
    } 

Если да, то как?

+0

Это звучит как [проблема XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem).Что вы пытаетесь сделать здесь, что хотите сделать это? И самое главное, почему вы не используете посетителя? * –

ответ

2

Нет, совсем нет. Вы должны посетить и разобраться со случаем каждого типа. Это гораздо лучше сделано с посетителем, чем с ручкой переключения.

1

Это невозможно, потому что boost::variant не знает, что все типы в variant имеют что-то общее. Фактически, поскольку компилятор генерирует отдельный класс для каждой используемой специализированной специализации, адрес функции Process(), который должен быть использован, различен для каждого типа в boost::variant. Чтобы обойти это, вы можете отказаться от variant и использовать виртуальные функции и полиморфные классы, имеющие общий базовый класс.

+0

Пример был бы действительно замечательным, я никогда в C++ не делал ничего похожего на базовый класс и класс пользователя: $ –

5

Что бы вернуть такую ​​функцию? Вы не можете изменить тип функции на времени выполнения. И пункт варианта заключается в том, что его содержимое определяется по адресу runtime.

Единственное, что он может вернуть, это boost::any. Который на самом деле просто обменивается одним видом неизвестного для другого (неизвестно, что это lot сложнее иметь дело, когда вы не знаете, что он содержит, заметьте). Но если вы хотите, чтобы увидеть такой посетитель:

struct convert_to_any : public boost::static_visitor<boost::any> 
{ 
    template<typename T> boost::any operator() (const T& t) {return t;} 
}; 

Используйте apply_visitor на это, и вы получите any назад. Хотя я не понимаю, как это полезно.


В любом случае, если вы используете get на variant, вы почти наверняка делать неправильные вещи. Правильный способ доступа к элементам варианта - с посетителем, а не с get.

В вашем случае, посетитель должен быть простым:

struct ProcessVisitor : public boost::static_visitor<> 
{ 
    template<typename T> void operator() (const T& t) const {t->Process();} 
}; 

Просто используйте apply_visitor по этому вопросу. Если вариант содержит тип, который может использоваться с operator->, и возвращаемое значение этой функции может иметь на нем Process10, то оно будет.

4

(Непроверенные код!)

struct CallProcess : static_visitor<> 
{ 
    template <class T> 
    void operator()(const T &t) const 
    { 
    t->Process(); 
    } 
}; 

for(auto i = Sliders.begin(); i != Sliders.end(); ++i) 
{ 
    boost::apply_visitor(CallProcess(), i->second); 
}