我正在(只为我自己)练习c++并试图"重新编码";c#属性。我知道这是没用的(我的意思是,我不会使用它)然而,我只是想尝试看看这是否可能。
由于某些原因,使用以下代码,在最新的clang/gcc版本下,除了-O0
(据我所知,它禁用了优化)之外,它并没有在每个优化标志下产生正确的结果。
#include <functional>
#include <iostream>
template<typename T>
class Property
{
private:
using getType = std::function<const T&(void)>;
using setType = std::function<void(const T&)>;
T internal;
getType get;
setType set;
public:
Property(const T &value) : internal{value}, get{[this] () { return internal; }}, set{[this](const T& value) { internal = value; }} {}
Property(getType fnc) : get(fnc) { }
Property(getType fncGet, setType fncSet) : get(fncGet), set(fncSet) { }
Property(setType fnc) : set(fnc) { }
Property(setType fncSet, getType fncGet) : get(fncGet), set(fncSet) { }
Property<T> &operator=(T& value) { set(value); return *this; }
operator const T&() const { return get(); }
};
int main(void)
{
Property<int> hey(12);
std::cout << hey << std::endl;
return hey;
}
它似乎在visual studio编译器下表现正确,但我不确定。
我是否错过了标准的一部分?我的代码不正确吗?clang/gcc/STL有bug吗?
我把我的代码放在一个叫Godbolt的网站上,以便在编译器之间轻松切换,但我得到了同样不连贯的结果。
下面是c++14/clang 14的打印内容:
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
624203080
最后一个数字在运行之间变化,但不是第一个,使我认为它只是使用未初始化的数据
您的问题是这部分:using getType = std::function<const T&(void)>;
与get{[this] () { return internal; }}
结合。
lambda在这里不返回internal
作为引用,因此返回internal
的副本,并且-在这里我不知道std::function
是如何实现的-std::function
必须持有internal
的副本,但返回它作为对该副本的引用,而不是悬空。
将其更改为get{[this] () -> T& { return internal; }}
似乎可以解决问题。
初始化get
的lambda按值返回,而不是按引用返回,这意味着返回的int
不再存在于std::function
机制中的某个地方。
你可以指定一个引用返回
[this] () -> const T& { return internal; }
的被害者。你应该使Property
不可复制和不可移动,因为你不能在复制或移动std::function
成员时重新指向this
捕获。