C++ 中数组对象的隐式类型转换
Implicit typecasting for array objects in C++
我几乎可以肯定这不可能,但我还是会问的。
我必须使用基于 C 的库,它将数字向量定义为浮点数组,并使用许多算术函数来使用它们。
我想创建一个简单的 class ,它可以很容易地转换为该类型,并添加有用的运算符。让我们看看 MWE:
#include <iostream>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
int main()
{
NewType t;
t[0] = 0.f; t[1] = 1.f; t[2] = 2.f;
const vector_type& v = t;
std::cout << "v(" << v[0] << "," << v[1] << "," << v[2] << ")" << std::endl;
return 0;
}
这完美无缺。当我们开始使用数组时,问题就出现了。让我们写一个新的主函数:
int main()
{
constexpr std::size_t size = 10;
vector_type v1[size]; // OK
NewType v2[size]; // OK
vector_type* v3 = v2; // No way, NewType* cannot be
// converted to float (*)[3]
vector_type* v4 =
reinterpret_cast<vector_type*>(v2); // OK
return 0;
}
reinterpret_cast
有效,但它使代码的可读性降低,并且 vector_type
和 NewType
之间的转换不透明。
据我所知,根据 C++11 和 C++14 标准,不可能使 NewType
class 隐式 castable使用数组。这是完全正确的吗?是否有任何允许此转换的注意事项?
P.s.: 请不要开始评论使用 reinterpret_cast 等的风险。 我知道这些风险,我知道编译器可以添加一些填充,我已经进行了一些 static_assert
检查以避免内存问题。
[编辑]我想让问题更容易理解。让我们举一个不同的例子:
struct original_vector
{
float x;
float y;
float z;
};
class NewType : public original_vector
{
public:
/* Useful functions here */
};
如果是我的话,一切都好办了! C 库中使用的类型是 original_vector
,我可以创建一个派生的 class 并且我可以添加任何类型的方法。
问题是,在我的实际情况下,original_vector
不是 class/struct,而是原始数组!显然,我不能继承它。也许现在我问这个问题的原因更清楚了。 ;)
#include <iostream>
#include <vector>
typedef std::vector<float> vector_type;
class NewType: public vector_type
{
public:
void MyMethod() {std::cout << "extending the vector type!" << std::endl;}
};
int main()
{
NewType myNewTypeVector[10];
myNewTypeVector[0] = NewType();
myNewTypeVector[0].push_back(1);
myNewTypeVector[0].push_back(2);
vector_type* p = myNewTypeVector;
std::cout << "Content of my_vector index 0: " << p[0][0] << std::endl;
std::cout << "Content of my_vector index 1: " << p[0][1] << std::endl;
std::cout << "Content of myNewTypeVector index 1: " << myNewTypeVector[0][1] << std::endl;
return 0;
}
我认为这不是最佳解决方案,但它是我认为使用 C++14 功能的最佳解决方案。也许,如果在未来的标准中引入运行时大小的成员分配(C++14 的提案已被拒绝),可能会有更好的解决方案。但是现在...
#include <iostream>
#include <memory>
#include <cassert>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
class NewTypeArray
{
public:
NewTypeArray() : size(0), newType(nullptr) {}
NewTypeArray(std::size_t size) : size(size) { assert(size > 0); newType = new NewType[size]; }
~NewTypeArray() { if(size > 0) delete[] newType; }
NewType& operator[](std::size_t i) { return newType[i]; }
operator vector_type* () { return static_cast<vector_type*>(&newType[0]); }
private:
std::size_t size;
NewType* newType;
};
static_assert(sizeof(NewType) == sizeof(vector_type) and sizeof(NewType[7]) == sizeof(vector_type[7]),
"NewType and vector_type have different memory layouts");
显然,NewTypeArray
可以修改,实现 面向向量的 方法,移动构造函数和赋值(就像在我的真实案例代码中一样)。
NewTypeArray
的实例可以直接传递给以 vector_type*
作为参数的函数,并且由于 static_assert
,内存管理应该不会有任何问题。
我几乎可以肯定这不可能,但我还是会问的。 我必须使用基于 C 的库,它将数字向量定义为浮点数组,并使用许多算术函数来使用它们。 我想创建一个简单的 class ,它可以很容易地转换为该类型,并添加有用的运算符。让我们看看 MWE:
#include <iostream>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
int main()
{
NewType t;
t[0] = 0.f; t[1] = 1.f; t[2] = 2.f;
const vector_type& v = t;
std::cout << "v(" << v[0] << "," << v[1] << "," << v[2] << ")" << std::endl;
return 0;
}
这完美无缺。当我们开始使用数组时,问题就出现了。让我们写一个新的主函数:
int main()
{
constexpr std::size_t size = 10;
vector_type v1[size]; // OK
NewType v2[size]; // OK
vector_type* v3 = v2; // No way, NewType* cannot be
// converted to float (*)[3]
vector_type* v4 =
reinterpret_cast<vector_type*>(v2); // OK
return 0;
}
reinterpret_cast
有效,但它使代码的可读性降低,并且 vector_type
和 NewType
之间的转换不透明。
据我所知,根据 C++11 和 C++14 标准,不可能使 NewType
class 隐式 castable使用数组。这是完全正确的吗?是否有任何允许此转换的注意事项?
P.s.: 请不要开始评论使用 reinterpret_cast 等的风险。 我知道这些风险,我知道编译器可以添加一些填充,我已经进行了一些 static_assert
检查以避免内存问题。
[编辑]我想让问题更容易理解。让我们举一个不同的例子:
struct original_vector
{
float x;
float y;
float z;
};
class NewType : public original_vector
{
public:
/* Useful functions here */
};
如果是我的话,一切都好办了! C 库中使用的类型是 original_vector
,我可以创建一个派生的 class 并且我可以添加任何类型的方法。
问题是,在我的实际情况下,original_vector
不是 class/struct,而是原始数组!显然,我不能继承它。也许现在我问这个问题的原因更清楚了。 ;)
#include <iostream>
#include <vector>
typedef std::vector<float> vector_type;
class NewType: public vector_type
{
public:
void MyMethod() {std::cout << "extending the vector type!" << std::endl;}
};
int main()
{
NewType myNewTypeVector[10];
myNewTypeVector[0] = NewType();
myNewTypeVector[0].push_back(1);
myNewTypeVector[0].push_back(2);
vector_type* p = myNewTypeVector;
std::cout << "Content of my_vector index 0: " << p[0][0] << std::endl;
std::cout << "Content of my_vector index 1: " << p[0][1] << std::endl;
std::cout << "Content of myNewTypeVector index 1: " << myNewTypeVector[0][1] << std::endl;
return 0;
}
我认为这不是最佳解决方案,但它是我认为使用 C++14 功能的最佳解决方案。也许,如果在未来的标准中引入运行时大小的成员分配(C++14 的提案已被拒绝),可能会有更好的解决方案。但是现在...
#include <iostream>
#include <memory>
#include <cassert>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
class NewTypeArray
{
public:
NewTypeArray() : size(0), newType(nullptr) {}
NewTypeArray(std::size_t size) : size(size) { assert(size > 0); newType = new NewType[size]; }
~NewTypeArray() { if(size > 0) delete[] newType; }
NewType& operator[](std::size_t i) { return newType[i]; }
operator vector_type* () { return static_cast<vector_type*>(&newType[0]); }
private:
std::size_t size;
NewType* newType;
};
static_assert(sizeof(NewType) == sizeof(vector_type) and sizeof(NewType[7]) == sizeof(vector_type[7]),
"NewType and vector_type have different memory layouts");
显然,NewTypeArray
可以修改,实现 面向向量的 方法,移动构造函数和赋值(就像在我的真实案例代码中一样)。
NewTypeArray
的实例可以直接传递给以 vector_type*
作为参数的函数,并且由于 static_assert
,内存管理应该不会有任何问题。