2013-05-08 2 views
3

У меня есть шаблон action, который принимает любой контейнер STL C. Однако содержащиеся в нем предметы (C::value_type) должны быть либо ClassA, либо ClassB. До сих пор так хорошо:C++ 11: Специализировать/ограничивать метод в зависимости от значения_таблицы контейнера

struct Whatever { 
    template<typename C> 
    void action(const C& c) { 
     static_assert(std::is_same<typename C::value_type, ClassA>::value || 
         std::is_same<typename C::value_type, ClassB>::value, 
         "Wrong C::value_type"); 
     // do something with c 
    } 
}; 

// Usage: 
Whatever w; 
w.action(std::vector<ClassA>{1, 2, 3}); 
w.action(std::unordered_set<ClassB>{1, 2, 3}); 

Примечание: класс вшита является не шаблон, единственный шаблон это очень action метод.

Теперь, в зависимости от C::value_type, я хочу специализироваться на поведении метода. Вы догадались, вот где мой мозг начинает таять.


Я считаю SFINAE это путь, но, очевидно, я слишком ржавым, чтобы заставить его работать правильно: после нескольких часов, тонны помощника structs и слишком много кофе для собственного здоровья, компилятор просто продолжает кричать обычные 500 + шаблонные ошибки у меня. Нет смысла копировать либо моего помощника structs, либо ошибки здесь, это почти бесполезный барахло.

Тем не менее, я должен признать, что я не поддерживал связь со всеми вариантами шаблонов C++ (r) (или даже использовал SFINAE), начиная с хорошего десятилетия, поэтому неудивительно, что я так сильно терпеть неудачу ,

Я сильно подозреваю, что C++ 11 теперь имеет простые, готовые к использованию инструменты, подобные SFINAE, для достижения того, что я хочу, но я даже не знаю, с чего начать поиск в документации. Поисковые системы тоже не помогли, для меня просто слишком много новой информации, чтобы я мог понять, что не имеет отношения к моей проблеме.

Поскольку я в полной потери, я просто принять шаги ребенка и спросить SO ... Мой вопрос заключается в два раза:

  • Как можно специализировать поведение метода в зависимости на фактическом типе C::value_type с использованием современных инструментов шаблонов C++ 11?
  • Возможно, есть стандартный способ проверить, действительно ли C является контейнером?

Благодарим за внимание.

ответ

3

Я задаюсь вопросом, почему бы вам не сделать это:

template<typename C> 
void action(const C& c) 
{ 
     static_assert(std::is_same<typename C::value_type, ClassA>::value || 
         std::is_same<typename C::value_type, ClassB>::value, 
         "Wrong C::value_type"); 

     action_worker(c, static_cast<typename C::value_type*>(0)); 
} 

private: 

template<typename C> 
void action_worker(const C& c, ClassA *) 
{ 
    //specialized code when C::value_type is ClassA 
} 

template<typename C> 
void action_worker(const C& c, ClassB *) 
{ 
    //specialized code when C::value_type is ClassB 
} 

Теперь в зависимости от C::value_type, второй аргумент action_worker может быть ClassA* или ClassB*. Это позволит компилятору выбрать правильную перегрузку, где вы пишете специализированный код.

Для второй части Вашего вопроса, увидеть реализацию is_container шаблона класса в этом ответе:

Надежда, что помогает.

+0

Ой, глупый меня ... Я * должен * думал об этом, но я искал в таком направлении, противоположном, что я вероятно, никогда не было бы. O_o Большое спасибо! Это, безусловно, отличный ответ на первую часть моего вопроса, очень прямолинейный. – syam

+0

@syam: См. Редактирование. Он ссылается на решение второй части вашего вопроса. – Nawaz

+0

Еще раз спасибо, вы прибили его. Хотел бы я снова поддержать тебя. ;) – syam

1

Как только поддерживать эти два типа, я бы рассмотреть вопрос об использовании enable_if:

struct Whatever 
{ 
    template<typename C> 
    typename std::enable_if<std::is_same<typename C::value_type, ClassA>::value, void>::type 
    action(const C& c) 
    { 
     std::cout << "ClassA\n"; 
    } 

    template<typename C> 
    typename std::enable_if<std::is_same<typename C::value_type, ClassB>::value, void>::type 
    action(const C& c) 
    { 
     std::cout << "ClassB\n"; 
    } 
}; 
+0

Действительно, это тот материал, из которого я был изначально. Спасибо, теперь у меня есть где начать расследование этих новых функций ... :) – syam