Сегмент конвейера C++ с несколькими выходными портами - сопоставление типов
Я пытаюсь спроектировать конвейер для моего проекта. Я слабо полагаюсь на концепцию трубопровода ВТК. Тем не менее, есть серьезные различия.
В моем проекте сопоставление типов соединений ввода-вывода было сделано с использованием шаблонов с переменным числом аргументов и рекурсивного наследования (аналогично CRTP). Это позволяет мне вручную определять, какие сегменты могут быть связаны с какими сегментами, передавая список абстрактных базовых классов базовым классам filter / mapper. Само по себе это не вызывает никаких проблем.
Мне нужно уметь работать с кастомами (не обязательно std
/ примитив) типы данных. Трубопровод VTK передает указатели на объекты, производные от одного из классов VTK (vtkAlgorithmObject
) через участки трубопровода. Это позволяет довольно естественную реализацию конвейерного интерфейса ввода / вывода с несколькими соединениями. Вот где моя проблема.
Внедрение VTK функции выходного порта:
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 ответа
Спасибо за комментарии и ответы. К сожалению, случайно я не включил определенную важную информацию в постановку задачи. getOutputPort2()
должен был быть членом класса, представляющего сегмент конвейера. Однако я не указал явно, что класс будет шаблоном. Таким образом, решения, основанные на явной специализации, неприменимы, поскольку необходимо специализировать как класс, так и шаблон функции-члена.
Решение, которое я решил использовать, основано на одном из ответов на следующий вопрос: явный вопрос специализации типа возврата. Пожалуйста, смотрите код ниже.
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!"));
}
};
};
Вы можете сделать что-то вроде:
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));
}