Сегмент конвейера 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));
}
Другие вопросы по тегам