2014-12-23 2 views
0

Я пытаюсь создать конвейер для моего проекта. Я свободно полагаюсь на концепцию трубопровода VTK. Однако существуют значительные различия.Сегмент конвейера C++ с несколькими выходными портами - соответствие типа

В моей конструкции сопоставление типа соединения ввода-вывода было выполнено с использованием вариативных шаблонов и рекурсивного наследования (аналогично CRTP). Это позволяет мне вручную определить, какие сегменты могут быть связаны с какими сегментами, передав список абстрактных базовых классов базовым классам фильтра/картографа. Само по себе это не вызывает никаких проблем.

Мне нужно иметь возможность работать с пользовательскими (не обязательно std/примитивными) типами данных. Трубопровод VTK передает указатели на объекты, которые производятся от одного из классов VTK (vtkAlgorithmObject) по сегментам трубопровода. Это позволяет довольно естественную реализацию интерфейса ввода/вывода конвейера с несколькими соединениями. Вот где моя проблема.

Реализация ВТК функции выходного порта является:

vtkAlgorithmOutput* vtkAlgorithm::GetOutputPort (int index) 

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

Один из способов сделать это с помощью комбинации аргументов шаблона и перегрузок:

template<int N> 
void getOutputPort(int& i) 
{ 
    if (N == 0) 
     i = 10; 
    else if (N == 2) 
     i = 20; 
    else 
     throw "Invalid template argument for the return type."; 
} 

template<int N> 
void getOutputPort(string& str) 
{ 
    if (N == 1) 
     str = "qwerty"; 
    else 
     throw "Invalid template argument for the return type."; 
} 

Однако, помимо очевидной проблемы разделения определения и выбора индекса над множеством функций, я должен вернуться по ссылке , что я не хотел бы делать. По этой концепции я хотел бы передать объекты через std::unique_ptr. Это гарантирует, что два сегмента, расположенные ниже по потоку, никогда не будут пытаться использовать один и тот же ресурс.

Таким образом, я пытаюсь сделать что-то подобное тому, что показано в коде ниже

template<int N> 
auto getOutputPort2() 
{ 
    if (N == 0) 
     return std::unique_ptr<int>(new int(10)); 
    else if (N == 1) 
     return std::unique_ptr<string>(new string("qwerty")); 
    else if (N == 2) 
     return std::unique_ptr<int>(new int(20)); 
    else 
     throw "Invalid template argument."; 
} 

По понятным причинам, это приводит к ошибке "несовместимым вычета авто. Существуют ли какие-либо способы решения проблемы (необязательно, используя auto)?

+2

Явная специализация? = – Columbo

ответ

0

Спасибо за вас комментарии и ответы. К сожалению, случайно, я не включил определенную важную информацию в постановку проблемы. getOutputPort2() должен был быть членом класса, который представляет сегмент конвейера. Однако я не указал явно, что класс будет шаблоном. Таким образом, решения, основанные на явной специализации, неприменимы, потому что необходимо специализировать как шаблон класса, так и элемент-член.

Решение, которое я решил использовать, основано на ответе на следующий вопрос: explicit return type specialisation question. Код, предназначенный для моей проблемы, приведен ниже:

template <typename T> 
class A 
{ 

public: 

    // the Get Value we want 
    template <int N> 
    auto getValue() 
     { 
      return get_value_impl<N>::apply(*this); 
     } 

    // the general get value struct 
    template<int N, typename = void> 
    struct get_value_impl 
    { 
     static auto apply(A a) 
      { 
       throw "Invalid template argument."; 
      } 
    }; 

    // partial specialization 1 
    template <typename S> 
    struct get_value_impl<0, S> 
    { 
     static std::unique_ptr<double> apply(A a) 
      { 
       return std::unique_ptr<double>(new double(10.0)); 
      } 
    }; 

    // partial specialization 2 
    template <typename S> 
    struct get_value_impl<1, S> 
    { 
     static std::unique_ptr<string> apply(A a) 
      { 
       return std::unique_ptr<string>(new string("Hello world!")); 
      } 
    }; 

}; 
1

Вы можете сделать что-то вроде:

template<int N> struct helper_type { 
    static_assert(N == 0 || N == 1 || N == 2, "Unexpected value"); 
    using type = typename std::conditional<N == 1, 
     std::unique_ptr<std::string>, 
     std::unique_ptr<int>>::type; 
}; 

/* only specializations are valid */ 
template<int N> 
typename helper_type<N>::type getOutputPort2() = delete; 

template<> 
typename helper_type<0>::type getOutputPort2<0>() 
{ 
    return std::unique_ptr<int>(new int(10)); 
} 

template<> 
typename helper_type<1>::type getOutputPort2<1>() 
{ 
    return std::unique_ptr<std::string>(new std::string("asdf")); 
} 

template<> 
typename helper_type<2>::type getOutputPort2<2>() 
{ 
    return std::unique_ptr<int>(new int(20)); 
} 
Смежные вопросы