c++ 差异但相关类型的模板运算符

nkoocmlb  于 2022-12-20  发布在  其他
关注(0)|答案(2)|浏览(130)

我正在为模板化的matrix<T>matrix_view<T>实现一些矩阵运算。

template <typename T, typename U>
matrix<common_type_t<T, U>> operator+(matrix_view<T>, matrix_view<U>);

并期望它也能适用于matrix

matrix<int> a, b;
auto c = a + b;

因为存在从matrix<T>matrix_view<T>的转换构造函数。
但它没有起作用,因为“类型推导不考虑隐式转换”规则。
所以我又加了一个过载

template <typename T, typename U>
matrix<common_type_t<T, U>> operator+(matrix<T>, matrix<U>);

但是故事还没有结束,对于matrix<T>matrix_view<T>之间的operator+,我需要定义另外两个重载来使它们工作。
现在我想知道我是否必须为每个矩阵运算定义所有的四个重载,这是很多样板代码,而且如果我将来要添加一些其他的类型,所需的重载的数量确实会随着所涉及的类型的数量呈指数增长。
这个问题有什么解决方法吗?最好只需要定义第一个重载。

xqk2d5yq

xqk2d5yq1#

使用一个概念:

template<typename C>
concept matrix_c = requires(C const& c) { [] <typename ... X>(matrix<X ...> const&) {}(c); }
                || requires(C const& c) { [] <typename ... X>(matrix_view<X ...> const&) {}(c); }

auto operator+(matrix_c auto&& m1, matrix_c auto&& m2);

此解决方案适用于matrix_viewmatrix的所有组合。
注意,如果你使用一个公共基类matrix_base,这个概念可以被简化,就像表达式模板代码中常见的那样,但是它也可以用于完全不相关的类。

7fyelxc5

7fyelxc52#

这就是我决定的解决方案,通过传统的方法专门化一个helper模板类。
@davidhigh的立即调用的lambda表达式(IILE)解决方案或std::convertible语义可能不像我在这里想要的那样准确。

// `is_specialization_of` shamelessly copied from this question
// https://stackoverflow.com/questions/70130735/c-concept-to-check-for-derived-from-template-specialization
template <typename T, template<typename...> typename Primary>
struct is_specialization_of : std::false_type {};

template <template<typename...> typename Primary, typename... Args>
struct is_specialization_of<Primary<Args...>, Primary> : std::true_type {};

// somehow I need to relax the condition a little to also allow const T and T&
template <template<typename...> typename Primary, typename T>
struct is_specialization_of<T&, Primary> : is_specialization_of<T, Primary> {};

template <template<typename...> typename Primary, typename T>
struct is_specialization_of<const T, Primary> : is_specialization_of<T, Primary> {};

template <typename T, template<typename...> typename Primary>
inline constexpr bool is_specialization_of_v = is_specialization_of<T, Primary>::value;

template <typename T>
concept matrix_like = is_specialization_of_v<T, matrix> ||
                      is_specialization_of_v<T, matrix_view>;

相关问题