шаблоны c ++, как сопоставить параметры шаблона с другими параметрами шаблона - PullRequest
2 голосов
/ 04 августа 2020

Можно как-нибудь сделать карту параметров шаблона? скажем, у меня есть следующая функция:

template<typename T>
T SumCoefficients(const std::vector<T>& coeffs) {
  T sum = static_cast<T>(0);
  for(int i=0; i<100; ++i) {
    sum += SomeFunc<T>(i) * coeffs[i];
  }
  return sum;
}

// explicit instantiation

template double SumCoefficients(const std::vector<double>& coeffs);
template float SumCoefficients(const std::vector<float>& coeffs);
template Vector3d SumCoefficients(const std::vector<Vector3d >& coeffs);

сейчас, допустим, я не хочу вызывать SomeFunc<T>(i), но вместо этого, если T == float, я хочу использовать SomeFunc<float>, если T == double Я хочу использовать SomeFunc<double>, но если T == Vector3d, я не хочу использовать SomeFunc<Vector3d>, а вместо SomeFunc<double>

теперь, конечно, я мог бы явно реализовать template <> Vector3d SumCoefficients(std::vector<Vector3d > coeffs) { ... }, а затем сделайте явный вызов SomeFunc<double>, но мне интересно, есть ли элегантный способ, который дает мне тот же результат только с одной реализацией шаблона плюс явное создание экземпляра.

Ответы [ 3 ]

3 голосов
/ 04 августа 2020

Подход constexpr if хорош, но я хотел бы добавить еще одно решение, которое я считаю предпочтительным, если у вас много вызовов SomeFunc в вашей кодовой базе.

Еще одно преимущество моего решения заключается в том, что он лучше масштабируется, если у вас много типов или вам нужно иметь возможность добавлять типы позже, потому что logi c сопоставления инкапсулирован в специализации шаблона, а не в вызывающем коде.

Я предполагаю, что вы С точки зрения семантики хотеть - это что-то вроде скалярного типа T:

template<typename T>
struct scalar_type {

    using type = T;
};

template<typename T>
using scalar_t = typename scalar_type<T>::type;

Теперь вы можете добавить отдельные характеристики этого шаблона для всех типов векторов, матриц или всего, что вам нужно.

template<>
struct scalar_type<Vector3d> {

    using type = double;
};

Ваш код вызова будет выглядеть так:

template<typename T>
auto SumCoefficients(const std::vector<T>& coeffs) {
  scalar_t<T> sum;
  for(int i=0; i<100; ++i) {
    sum += SomeFunc<scalar_t<T>>(i) * coeffs[i];
  }
  return sum;
}

Если вы ограничены c ++ 11, сайт вызова может выглядеть так:

template<typename T, typename Scalar = scalar_t<T>>
Scalar SumCoefficients(const std::vector<T>& coeffs) {
  Scalar sum;
  for(int i=0; i<100; ++i) {
    sum += SomeFunc<Scalar>(i) * coeffs[i];
  }
  return sum;
}

См. Полный пример здесь

3 голосов
/ 04 августа 2020

Вы можете использовать constexpr if (начиная с C ++ 17) для проверки типа. например,

template<typename T>
T SumCoefficients(const std::vector<T>& coeffs) {
  T sum = static_cast<T>(0);
  for(int i=0; i<100; ++i) {
    if constexpr (std::is_same_v<T, Vector3d>) // when T is Vector3d
      sum += SomeFunc<double>(i) * coeffs[i];
    else
      sum += SomeFunc<T>(i) * coeffs[i];
  }
  return sum;
}
2 голосов
/ 04 августа 2020

Вы запросили решение C ++ 11, которое не может использовать if constexpr:

template<typename T>
T SumCoefficients(const std::vector<T>& coeffs) {
  using TTag = typename std::conditional<std::is_same<T, Vector3d>::value, double, T>::type;
  TTag sum = static_cast<TTag>(0);
  for(int i=0; i<100; ++i) {
    sum += SomeFunc<TTag>(i) * coeffs[i];
  }
  return sum;
}

(я сделал некоторые предположения относительно возвращаемого типа SomeFunc и, возможно, чего-то еще, поскольку ваш в вопросе не было полной информации, но я надеюсь, что это сработает для вас)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...