模板化类的自动类型推导强制

auto type deduction coercion for templated class?

本文关键字:类型      更新时间:2023-10-16

我在构建的模板类中有 2 个问题。我在下面包含了示例代码。第一个问题是我是否可以强制为模板化类扣除自动类型,即:

自动 p = myvar;

myvar 是 T<...>,我可以强制自动检测 Q<...> 吗?这是简化的。请继续阅读以获得更清晰的解释。

为清楚起见进行了编辑:让我解释一下我在做什么。我还想指出,这种风格代码在一个大型项目上工作得很好。我正在尝试添加一些特性和功能,此外还消除了一些更尴尬的行为。

该代码使用模板对 n 维数组执行工作。模板具有一个顶级类,其下有一个存储类。将存储类传递到顶级类允许使用继承存储类的顶级类。所以我从NDimVar开始,我有NDimStor。我最终得到

NDimVar<NDimStor>

该类不包含除数据缓冲区外的任何数据:

class NDimStor<size_t... dimensions> {
int buffer[Size<dimensions...>()]
}

这使得类的地址 == 成为缓冲区的地址。这是整个实现的关键。这是一个不正确的假设吗?(我可以看到这在我的系统上没有任何问题,但也许情况并非总是如此。

当我创建 NDimVar<10,10>>我最终得到一个 10x10 的数组。

我有用于获取数组片段的函数,例如:

NDimVar<NDimStor<dimensions...>>::RemoveDim & get(int index);

这将从 2d 10x10 数组中创建包含 10 个元素的新 1d 数组:

NDimVar<NdimStor<10>>

为了将其作为引用返回,我在所需数据的位置使用reinterpret_cast。所以在这个例子中, get(3) 将执行:

return reinterpret_cast<NDimVar≤NDimStor<dimensions...>>::RemoveDim&>(buffer[index * DimensionSumBelow<0>()]);

DimensionSumBelow<0> 返回维度为 1+ 的元素之和,即 10。所以 &buffer[30] 是引用的 1d NDimVar 的地址。

所有这些都非常有效。

我唯一的问题是我想添加叠加层。例如,能够返回对新类的引用:

NDimVar<NDimPermute<NDimStor<10,10>,1,0>>

指向相同的原始位置以及排列行为(交换维度)。这也很好用。但我想:

auto p = myvar.Permute<1,0>()

创建具有排列数据的 myvar 的新副本。如果我说:

NDimVar<NDimStor<10,10>> p = myvar.Permute<1,0>().

我觉得我可以做一些自动类型扣除的事情来强制返回的自动类型,但我不确定。我一直想不通。

再次感谢, 纳楚姆

我想要的是: 1. 在我的存储上创建临时覆盖类,例如A_top可以在不创建新对象的情况下返回一个名为 A_top> 的类型,它只返回对该类型的引用。这将更改访问存储的方式。问题出在调用自动时。我不希望直接实例化此类型。我可以将返回自动修改为原始A_top吗?

#include <iostream>
using namespace std;
class A_storage {
public:
float arr[10];
A_storage () {
}
float & el (int index) {
return arr[index];
}
};
template <typename T> class A_overlay : T {
private:
A_overlay () {
cout << "A_overlay  ()" << endl;
}
A_overlay (const A_overlay  &) {
cout << "A_overlay  (&)" << endl;
}
public:
using T::arr;
float & el (int index) {
return arr[10 - index];
}
};
template <typename T> class A_top;
template <typename T> class A_top : public T {
public:
A_top () {
}
A_top<A_overlay<A_storage>> & get () {
return reinterpret_cast<A_top<A_overlay<A_storage>>&>(*this);
}
};
using A = A_top<A_storage>;
int main (void) {
A a;
auto c = a.get(); // illegal - can i auto type deduce to A_top<A_storage>?
return 0;
}
  1. 如果一个函数接受(A_top&)作为参数,我怎样才能创建一个可以转换A_top>&到A_top&的转换函数?

谢谢 纳楚姆

首先,你的设计对我来说看起来不对,我不确定行为是否真的定义得很好。 (可能不是。

无论如何,问题不在于auto.该错误是由于A_overlay的复制构造函数是私有的,而您需要它来复制A_top<A_overlay<A_storage>>a.get()返回auto c

(请注意,在这种情况下auto显然被推断为A_top<A_overlay<A_storage>>,我假设您在说它A_top<A_storage>时犯了一个错字。


另请注意,A_top::get()中的A_storage应替换为T,即使它不会更改代码段中的任何内容,因为您只有T == A_storage


如果函数接受 (A_top &) 作为参数,如何创建一个可以将A_top>转换为 A_top 的转换函数?

嗯,不就是这样吗:

return reinterpret_cast<A_top<A_storage>&>(obj);
reinterpret_cast

几乎不应该使用。它实质上删除了类型相关的任何编译器验证。执行不相关的强制转换本质上是未定义的行为,因为它本质上假设派生类始终处于偏移量 0...

编写这样的代码没有任何意义。它是不可维护的,也很难理解您要实现的目标。看起来您想假装您的A_top<A_storage>对象是A_top<A_overlay<A_storage>>对象。如果这是您要执行的操作,则A别名声明为该类型。

在您的代码中,您似乎想要反转索引,以便在询问位置 0 的项时返回位置 10 的项,反之亦然。你真的认为,从你的混淆代码中很明显吗?永远不要写这么糟糕的代码。

类似的东西

class A_overlay {
public:
float & el (int index) { return arr[10 - index]; }
private:
A_storage arr;
};

会比您当前的代码更有意义。

  • 无需演员表。
  • 易于理解。
  • 明确定义的行为。
  • 你可能会保住你的工作。

显然,您将根据需要更新以下行:

using A = A_top<A_storage>;

另外,如果A_top没有有用的目的,那么为什么不直接使用A_overlay呢?如果模板不是模板,为什么要使用模板A_storage?你真的想在你的代码库中的其他地方重用这种混乱吗?

显然,如果您编写此类代码,则代码继承不尊重 IS-A 关系。所以这显然是一个糟糕的设计!