我正在通过实现线性代数库来试验 C++ 中的模板,因此这个示例可能不是最适合这项工作。
假设我有一个 N 维容器,其中包含我想要继承的数据和向量和矩阵的常用函数(我知道,定义 Matrix 类型然后使用
using
声明是一种常见的做法不同的线性代数类型,就像它们在 eigen 中所做的那样,但我想继承这个容器,然后向各种类型添加方法,同样,它可能不是最合适的,但它是一个实验)。
template <typename T, std::size_t... Dims>
class NDimContainer {
public:
auto operator+=(const NDimContainer &other) {
std::transform(elems.begin(), elems.end(), other.begin(), std::plus<T>());
return *this;
}
private:
std::array<T, (... * Dims)> elems;
};
template <typename T, std::size_t Dims>
class Vector : public NDimContainer<T, Dims> { ... }
问题是:是否可以像这样访问模板中指定的模板参数
N
和Dims...
:
template <template<typename N, std::size_t... Dims> typename T>
require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>>
auto operator+(const T &lhs, const T& rhs) {
return T { lhs } += rhs;
}
我知道可以这样做:
template <template<typename, std::size_t...> typename T, typename N, std::size_t... Dims>
require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>>
auto operator+(const T &lhs, const T& rhs) { ... }
但是模板将无法匹配,例如
Vector
类型(或者至少在我的情况下没有,如果是一些微不足道的错误,请纠正我)。
有什么方法可以让这项工作顺利进行,以便我可以做这样的事情吗?
Vector<int, 3> a = Vector<int, 3>() + Vector<int, 3>();
我在此处和此处找到了有关此主题的先前问题。但这些都不能真正解决我的用例。
禁止更简单的解决方案的罪魁祸首是
Dims...
,因为我不知道如何做这样的事情:
template <typename T, std::size_t... Dims>
class A {
public:
using Type = T;
using Dimensions = Dims...; // Error
};
std::integer_sequence
,但这会带来额外的空间成本,我不想付费。
我尝试过这样的事情:
template <template<typename N, std::size_t... Dims> typename T, typename NN = N, std::size_t... DDims = Dims>
require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>>
auto operator+(const T &lhs, const T& rhs) { ... }
但这显然也行不通。
是否可以进行类似的构造?
编辑:添加最小的可重现示例
#include <array>
template<typename T, std::size_t ... Dims>
struct A {
std::array<T,(Dims*...)> data = {};
A& operator+=( const A& ) noexcept;
};
// This works, but only for because of the conversion that is defined in Vector type
template<typename T, std::size_t... Dims>
auto operator+( const A<T,Dims...>& lhs, const A<T,Dims...>& rhs) -> A<T,Dims...> {
return A{lhs} += rhs;
}
// This is the one I would like it matched instead, because then it would be instantiated for
// particular type.
template<template<typename TT, std::size_t ... DD> typename T1, typename T, std::size_t... Dims>
auto operator+( const A<T,Dims...>& lhs, const A<T,Dims...>& rhs) -> A<T,Dims...> {
return A{lhs} += rhs;
}
template<typename T, std::size_t N>
struct Vector : A<T,N> {
using Base = A<T,N>;
Vector() = default;
Vector(const Base& base) : Base(base) {}
};
using Vector3d = Vector<double,3>;
int main() {
Vector3d vec = Vector3d{} + Vector3d{};
return 0;
}
您的问题太长,里面的问题太多。我会重点关注这个:
问题是:是否可以访问模板中指定的模板参数 N 和 Dims...,如下所示:
template <template<typename N, std::size_t... Dims> typename T> require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>> auto operator+(const T &lhs, const T& rhs) { return T { lhs } += rhs; }
不。这里
template <template<typename N, std::size_t... Dims> typename T>
你说的是 T
是一个带有参数 N
和 Dims...
的模板。您可以实例化 T
,但无法从 T
推导出 N
和 Dims...
的值,因为它们是参数。
您所问的内容类似于:“给定一个以
f
作为参数的函数 int x
,我能找出 x
的值是多少吗?”。当然不是。 f
是一个可以传递任何 x
的函数。
我感觉模板模板参数的使用毫无意义,就像我以前见过的那样。我想你实际上想要这样的东西:
template <typename T>
require std::is_derived_from<NDimContainer<T>>
auto operator+(const T &lhs, const T& rhs) {
return T { lhs } += rhs;
}
其中
T
是具有参数 N
和 Dims..
的某个模板的实例。如果是这种情况,那么您可以从该实例化 T
(一种类型)、参数 N
和 Dim...
中推断出 T
与某些 U<N,Dims...>
的类型相同。这是可能的,但这是一个不同的问题。