我正在尝试 lambda 函数,并设法在 C++ 中重新创建“获取”功能。我可以在不使用括号的情况下获取函数的返回值。这是一个示例类,我在其中实现:
using namespace std;
struct Vector2 {
float x;
float y;
float length = [&]()-> float {return sqrt(x * x + y * y); }();
float angle = [&]()-> float {return atan2(y, x); }();
Vector2() : x(0), y(0) {}
Vector2(float a, float b) : x(a), y(b) {}
~Vector2() {}
Vector2(Vector2& other) : x(other.x), y(other.y) {}
Vector2(Vector2&& other) = delete;
void operator =(Vector2&& other) noexcept{
x = other.x;
y = other.y;
}
};
int main()
{
Vector2 vec = Vector2(10, 17);
printf("%f\n%f\n%f\n%f\n", vec.x, vec.y, vec.length, vec.angle);
}
Run Code Online (Sandbox Code Playgroud)
不过,我目前正在尝试重新创建 C# 具有的“设置”功能。但我失败了。我尝试添加这个:
void angle = [&](float a)->void {
float l = length;
x = cos(a) * l;
y = sin(a) * l;
};
Run Code Online (Sandbox Code Playgroud)
但收到“不允许不完整的类型”错误。我不确定它是否应该是这样的,即使我没有收到错误。是否有可能在 C++ 中重新创建 C# 的“设置”功能?
我知道我可以只使用一个方法SetAngle(float a){...},但这不是重点。
TL;DR:不要
你所拥有的不是一个 getter,它只是一个普通的数据成员,在对象初始化时计算一次。
一般来说,C++ 不支持 C# 样式的属性。通常的 C++ 风格的解决方案是仅使用一对成员函数(如果需要单独保存值,可能还使用一个数据成员),即
struct Vector2 {
// ...
float length() const { return sqrt(x * x + y * y); }
void length(float l) {
float angle = angle();
float new_x = l * cos(angle);
float new_y = l * sin(angle);
x = new_x;
y = new_y;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
您可以获得一些接近 C# 风格的属性,但您总是会遇到它们不能完美工作的边缘情况。例如,以下内容在许多情况下都适用:
template <typename T>
class Property
{
private:
std::function<T()> getter_;
std::function<void(const T&)> setter_;
public:
Property(std::function<T()> getter, std::function<void(const T&)> setter)
: getter_{getter},
setter_{setter}
{}
operator T()
{
return getter_();
}
const T& operator=(const T& val)
{
setter_(val);
return val;
}
};
struct Vector2
{
float x;
float y;
Property<float> length{
[this]() { return sqrt(x * x + y * y); },
[this](float l) {
float new_x = l * cos(angle);
float new_y = l * sin(angle);
x = new_x;
y = new_y;
}
}
Property<float> angle{
[this]() { return atan2(y, x); },
[this](float a) {
float l = length;
x = cos(a) * l;
y = sin(a) * l;
}
}
// ...
};
int main() {
Vector2 v;
v.x = 1;
v.y = 1;
v.angle = std::numbers::pi / 2;
std::cout << "(" << v.x << ", " << v.y << ")\n";
}
Run Code Online (Sandbox Code Playgroud)
但这在边缘情况下仍然会崩溃,特别是当您将其与模板和/或auto类型推导混合时。例如:
Vector2 v;
v.x = 1;
v.y = 1;
auto old_angle = v.angle;
v.angle = std::numbers::pi / 2;
// oops, this prints pi/2, not pi/4 like you probably expected
// because old_angle isn't a float, it's a Property<float> that
// references v
std::cout << old_angle << '\n';
Run Code Online (Sandbox Code Playgroud)
另请注意,这里有一个错误。考虑一下:
int main() {
Vector2 v1;
v1.x = 1;
v1.y = 1;
Vector2 v2 = v1;
v2.angle = std::numbers::pi / 2;
// Oops, assigning to v2.angle modified v1
std::cout << "(" << v1.x << ", " << v1.y << ")\n";
}
Run Code Online (Sandbox Code Playgroud)
您可以通过设置不可复制来解决这些问题Property,但随后您会强制使用它的任何类来实现自定义复制构造函数。另外,虽然这会使auto情况变得“安全”,但它是通过将其转变为编译错误来实现的。还是不理想。