C ++: `enable_if` для ограничения типов, которые поддерживают определенные арифметические операции - PullRequest
2 голосов
/ 04 июня 2019

Я хотел бы определить шаблонную функцию, которая может применяться только к типам, которые поддерживают умножение, например int, long, float и пользовательские типы с перегруженными операторами, такими как Martix:

class Matrix {
    public:
        Matrix operator*(const Matrix& other) const;
}

Можно ли таким образом ограничить тип шаблона?

template <typename T, typename = std::enable_if_t< /* multiplication is defined */ >>
T power (T base, unsigned int exponent) {
    // ...
}

Ответы [ 2 ]

6 голосов
/ 04 июня 2019

Если вам нужно только проверить, можно ли умножить тип на себя, вы можете использовать:

template <class T, 
          class = decltype(std::declval<T>() * std::declval<T>())>
T power (T base, unsigned int exponent) {
     ...
}
3 голосов
/ 04 июня 2019

Взгляните на is_detected из основы TS v2 (также возможна реализация). Это дает вам хорошую базу на случай частых проверок различных операций. Это в основном позволяет вам проверить, возможна ли указанная операция с данными типами.

Сначала вы определяете тип вашей операции:

template <typename Lhs, typename Rhs>
using multiplication_t = decltype(std::declval<Lhs>() * std::declval<Rhs>());

затем вы делаете из него черту типа:

template <typename Lhs, typename Rhs>
constexpr bool can_multiply = is_detected<multiplication_t, Lhs, Rhs>::value;

Теперь вы можете использовать черту в качестве условия для enabled_if:

template <typename T, typename = std::enable_if_t<can_multiply<T, unsigned int>>
T power (T base, unsigned int exponent) {
    // ...
}

Это также добавляет читабельность (по крайней мере, imo), потому что can_multiply четко выражает ваше намерение.

Здесь - полная реализация в качестве примера.

Еще один пример с большим количеством операций.

...