Функция обратного вызова в шаблонной функции, принимающей переменный тип аргумента с помощью оператора `switch`

#c #templates #vector #c 14

Вопрос:

Я пытаюсь вызвать функцию обратного вызова из шаблонной функции. Но аргументы функции обратного вызова зависят от switch оператора.

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

 #include <vector>

struct A {};
struct B {};
struct C {};
struct D {};

enum class StructType
{
  A,
  B,
  C,
  D
};

std::vector<A> vec_A;
std::vector<B> vec_B;
std::vector<C> vec_C;
std::vector<D> vec_D;


template <template <class> class Container, class ValueType>
void process(const StructTypeamp; struct_type)
{
  auto callback = [amp;](Container<ValueType>amp; v) {};

  switch(struct_type)
  {
    case StructType::A:
      callback(vec_A);
      break;
    case StructType::B:
      callback(vec_B);
      break;
    case StructType::C:
      callback(vec_C);
      break;
    case StructType::D:
      callback(vec_D);
      break;
  }
}


int main()
{
  process<std::vector, A>(StructType::A);

}
 

При компиляции я получаю следующую ошибку:

 $ g   template.cpp 
template.cpp: In instantiation of ‘void process(const StructTypeamp;) [with Iterator = std::vector; ValueType = A]’:
template.cpp:47:26:   required from here
template.cpp:33:15: error: no match for call to ‘(process<std::vector, A>(const StructTypeamp;)::<lambda(std::vector<A>amp;)>) (std::vector<B>amp;)’
   33 |       callback(vec_B);
      |       ~~~~~~~~^~~~~~~
template.cpp:25:19: note: candidate: ‘process<std::vector, A>(const StructTypeamp;)::<lambda(std::vector<A>amp;)>’
   25 |   auto callback = [amp;](Iterator<ValueType>amp; v) {};
      |                   ^
template.cpp:25:19: note:   no known conversion for argument 1 from ‘std::vector<B>’ to ‘std::vector<A>amp;’
template.cpp:36:15: error: no match for call to ‘(process<std::vector, A>(const StructTypeamp;)::<lambda(std::vector<A>amp;)>) (std::vector<C>amp;)’
   36 |       callback(vec_C);
      |       ~~~~~~~~^~~~~~~
template.cpp:25:19: note: candidate: ‘process<std::vector, A>(const StructTypeamp;)::<lambda(std::vector<A>amp;)>’
   25 |   auto callback = [amp;](Iterator<ValueType>amp; v) {};
      |                   ^
template.cpp:25:19: note:   no known conversion for argument 1 from ‘std::vector<C>’ to ‘std::vector<A>amp;’
template.cpp:39:15: error: no match for call to ‘(process<std::vector, A>(const StructTypeamp;)::<lambda(std::vector<A>amp;)>) (std::vector<D>amp;)’
   39 |       callback(vec_D);
      |       ~~~~~~~~^~~~~~~
template.cpp:25:19: note: candidate: ‘process<std::vector, A>(const StructTypeamp;)::<lambda(std::vector<A>amp;)>’
   25 |   auto callback = [amp;](Iterator<ValueType>amp; v) {};
      |                   ^
template.cpp:25:19: note:   no known conversion for argument 1 from ‘std::vector<D>’ to ‘std::vector<A>amp;’
 

Моя g версия такова: 11.1.0 .

Я могу понять ошибку, но просто не знаю, как это исправить.

Мы будем очень признательны за любую помощь. Спасибо.

ПРАВКА 1: Iterator -> > Container для типа шаблона имеет больше смысла, как предложил @Ted Lyngmo.

Комментарии:

1. У вас есть аргумент функции, который известен только во время выполнения, но он зависит от типа времени компиляции в параметре шаблона. Вам действительно нужен аргумент времени выполнения в этом случае? Пример Не связан: Iterator это странное имя для параметра шаблона. Container может быть, это подойдет лучше.

2. Итак, ты предлагаешь мне просто использовать auto callback = [amp;](const autoamp; v) {}; ? Потому что это не компилируется с использованием -std=c 14 флага.

3. Я задаюсь вопросом, почему вы должны снабжать StructType::A process кого-то . Что должно произойти, если вы позвоните с process<std::vector, A>(StructType::B); этим ?

4. Это был всего лишь игрушечный пример. В реальной реализации process вызывается с различными типами Struct , я просто хотел смоделировать это поведение здесь , используя Struct::A в качестве примера. Или, скорее, скажем, процесс передается с контейнером, который содержит различные типы векторных данных, которые вызывают callback .

5. Итак, из аргумента функции StructType::A вы знаете, что она должна использовать a std::vector<A> — но эта информация уже содержится в параметрах шаблона (как я показал в своем примере вверху). Я все еще не вижу причины для предоставления той же информации с помощью аргумента времени выполнения.

Ответ №1:

Как говорят ваши ошибки, нет совпадений для callback функторов, которые вы не создали.

Я предлагаю удалить аргумент времени выполнения process и использовать информацию, которую вы имеете только в параметрах шаблона функции.

Пример:

 #include <vector>
#include <type_traits>

struct A {};
struct B {};
struct C {};
struct D {};

// enum class StructType {A, B, C, D }; // perhaps not needed anymore

std::vector<A> vec_A;
std::vector<B> vec_B;
std::vector<C> vec_C;
std::vector<D> vec_D;

template<class T> autoamp; get_vec();
template<> autoamp; get_vec<std::vector<A>>() { return vec_A; }
template<> autoamp; get_vec<std::vector<B>>() { return vec_B; }
template<> autoamp; get_vec<std::vector<C>>() { return vec_C; }
template<> autoamp; get_vec<std::vector<D>>() { return vec_D; }

template <template <class, class...> class Container, class ValueType>
void process() {
    using container_type = Container<ValueType>;

    auto callback = [amp;](container_typeamp;) {};
    callback(get_vec<container_type>());
}

int main() {
    process<std::vector, A>();
}