【发布时间】:2021-09-15 13:48:09
【问题描述】:
我正在尝试为不同的模板类型提供算术运算符+-*/(和就地+= 等)的类外定义。我读到 C++20 概念是一个很好的方法,因为可以限制输入/输出类型以仅提供一个模板定义,尽管我找不到太多这样的例子......
我使用类型安全的向量作为基类:
// vect.cpp
template<size_t n, typename T>
struct Vect {
Vect(function<T(size_t)> f) {
for (size_t i=0; i < n; i++) {
values[i] = f(i);
}
}
T values [n];
T operator[] (size_t i) {
return values[i];
}
}
我有一个张量的派生类,如下所示:
// tensor.cpp
template <typename shape, typename T>
struct Tensor : public Vect<shape::size, T> {
// ... same initiliazer and [](size_t i)
}
我还将为只读视图/切片定义一个派生类,覆盖operator [] 以跨越大步。我只想在每个类中硬编码fmap 和fold 方法,并尽可能避免复制样板代码。
由于模板参数不同,我首先在为Vect<n,T> 类的类提出合适的概念时遇到了一些麻烦,但下面的那个似乎可行:
// main.cpp
template<typename V, int n, typename T>
concept Vector = derived_from<V, Vect<n, T>>
template<int n, typename T, Vector<n, T> V>
V operator + (const V& lhs, const V& rhs) {
return V([&] (int i) {return lhs[i] + rhs[i];});
}
int main () {
size_t n = 10;
typedef double T;
Vect<n,T> u ([&] (size_t i) {return static_cast<T>(i) / static_cast<T>(n);});
log("u + u", u);
return 0;
}
Error: template deduction/substitution failed, could not deduce template parameter 'n'
尝试 2:
基于this question,我认为类外定义必须更冗长一些,所以我在vect.cpp 中添加了几行。
这似乎是人为的,因为它需要 (3 * N_operators) 类型签名定义,其中避免代码重复是引发这个问题的原因。另外,我真的不明白 friend 关键字在这里做什么。
// vect.cpp
template<size_t n, typename T>
struct Vect;
template<size_t n, typename T>
Vect<n, T> operator + (const Vect<n, T>& lhs, const Vect<n, T>& rhs);
template<size_t n, typename T>
struct Vect {
...
friend Vect operator +<n, T> (const Vect<n, T>& lhs, const Vect<n, T>& rhs);
...
}
Error: undefined reference to Vect<10, double> operator+(Vect<10, double> const&, Vect<10, double> const&)' ... ld returned 1 exit status
我猜编译器会抱怨在 main.cpp 而不是 vect.cpp 中定义的实现?
问题:正确的 C++ 方法是什么?有什么方法可以让编译器满意,例如有头文件吗?
我真的在这里寻找 DRY 答案,因为我知道代码可以使用大量的复制粘贴 :)
谢谢!
【问题讨论】:
-
关于 try 2:模板通常在头文件中声明和定义,否则可能会导致链接器错误(更多关于它here)。
-
你的 lambda 需要一个明确的
static_cast<T>。所以[&] (size_t i) {return static_cast<T>(i) / static_cast<T>(n);}或模板化的 lambda。目前u初始化为0。 -
您不能覆盖非虚拟函数。
-
@2b-t 感谢您的指点。适合
static_cast<T>写(T)i / (T)n也可以 -
@shevket
(T)的表达力不如static_cast<T>(...)。(T)在不同的上下文中可能意味着非常不同的东西:See here
标签: c++ templates linear-algebra c++20 derived-class