让 class 继承模板类型的所有运算符
Having class inherit all operators of template type
我创建了这个 class 这样我就可以得到任何类型的值,每次使用时它要么是固定的要么是重新计算的:
template <typename T>
class DynamicValue {
private:
std::variant<T, std::function<T()>> getter;
public:
DynamicValue(const T& constant) : getter(constant){};
template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
DynamicValue(F&& function) : getter(function) {}
DynamicValue(const T* pointer) : DynamicValue([pointer]() { return *pointer; }) {}
DynamicValue(const DynamicValue& value) : getter(value.getter) {}
~DynamicValue() {}
DynamicValue& operator=(const DynamicValue& value) {
getter = value.getter;
return *this;
}
operator T() {
return getter.index() == 0 ? std::get<T>(getter) : std::get<std::function<T()>>(getter)();
}
};
我还编写了以下虚拟结构来展示我的问题:
struct A {
int b;
};
问题是,理想情况下,我能够将任何 DynamicValue<T>
视为类型 T
。因此,如果我要创建一个新值 (DynamicValue<A> a = A{1};
),我将能够执行 a.b
并获取由 a
计算的值的属性 b
。但是,我收到以下错误:
'class DynamicValue' has no member named 'b'
您可以尝试一个实例 here。
我的问题是:有没有办法克服这个问题,或者我必须接受 ((A) a).b
语法?我考虑过重载每个运算符以实现我的目标,但此解决方案不适用于 .
运算符(和其他运算符),它们不可重载,并且可能有其自身的问题。
The problem is, ideally, I'd be able to treat any DynamicValue<T>
as if it were of type T
. So if I were to create a new value (DynamicValue<A> a = A{1};
), I'd be able to do a.b
and get the attribute b of the value calculated by a
.
这将需要 operator.
重载或委托继承。两者在 C++ 中都不可用。
我会推荐两个模型:operator()
重载或 operator*
。
重载调用运算符将使您的 DynamicValue
看起来像一个函数,无论它包含一个函数还是一个值:
DynamicValue<A> a = A{1};
auto real_a = a();
std::cout << real_a.b;
如果重载取消引用运算符,您的 class 看起来就像一个指向值的指针,无论它是值还是函数:
DynamicValue<A> a = A{1};
auto real_a = *a;
std::cout << real_a.b;
我会小心 operator->
,因为如果您的动态值包含函数,它可能会导致性能显着下降。
我会完全避免隐式转换运算符,因为它带有很多警告和陷阱。这是一把很棒的脚枪,必须谨慎使用。
我创建了这个 class 这样我就可以得到任何类型的值,每次使用时它要么是固定的要么是重新计算的:
template <typename T>
class DynamicValue {
private:
std::variant<T, std::function<T()>> getter;
public:
DynamicValue(const T& constant) : getter(constant){};
template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
DynamicValue(F&& function) : getter(function) {}
DynamicValue(const T* pointer) : DynamicValue([pointer]() { return *pointer; }) {}
DynamicValue(const DynamicValue& value) : getter(value.getter) {}
~DynamicValue() {}
DynamicValue& operator=(const DynamicValue& value) {
getter = value.getter;
return *this;
}
operator T() {
return getter.index() == 0 ? std::get<T>(getter) : std::get<std::function<T()>>(getter)();
}
};
我还编写了以下虚拟结构来展示我的问题:
struct A {
int b;
};
问题是,理想情况下,我能够将任何 DynamicValue<T>
视为类型 T
。因此,如果我要创建一个新值 (DynamicValue<A> a = A{1};
),我将能够执行 a.b
并获取由 a
计算的值的属性 b
。但是,我收到以下错误:
'class DynamicValue' has no member named 'b'
您可以尝试一个实例 here。
我的问题是:有没有办法克服这个问题,或者我必须接受 ((A) a).b
语法?我考虑过重载每个运算符以实现我的目标,但此解决方案不适用于 .
运算符(和其他运算符),它们不可重载,并且可能有其自身的问题。
The problem is, ideally, I'd be able to treat any
DynamicValue<T>
as if it were of typeT
. So if I were to create a new value (DynamicValue<A> a = A{1};
), I'd be able to doa.b
and get the attribute b of the value calculated bya
.
这将需要 operator.
重载或委托继承。两者在 C++ 中都不可用。
我会推荐两个模型:operator()
重载或 operator*
。
重载调用运算符将使您的 DynamicValue
看起来像一个函数,无论它包含一个函数还是一个值:
DynamicValue<A> a = A{1};
auto real_a = a();
std::cout << real_a.b;
如果重载取消引用运算符,您的 class 看起来就像一个指向值的指针,无论它是值还是函数:
DynamicValue<A> a = A{1};
auto real_a = *a;
std::cout << real_a.b;
我会小心 operator->
,因为如果您的动态值包含函数,它可能会导致性能显着下降。
我会完全避免隐式转换运算符,因为它带有很多警告和陷阱。这是一把很棒的脚枪,必须谨慎使用。