C ++可链接属性

时间:2012-11-26 11:26:51

标签: c++ templates

我正在尝试创建一个名为“可链接属性”的相对类型安全(但动态)且高效的概念。可链接属性类似于C#绑定属性的能力,类似于信号/插槽模型。

可链接属性是一种可以将自身链接到其他类型的值的类型。当任何值更改时,所有值都会更新。当您需要同时更新多个属性/值时,这非常有用。设置链接后,一切都会为您完成。

  1. 可以从任何类型链接到任何其他类型(理论上,这是问题)
  2. 链接使用链接列表而不是列表。这在内存和速度方面都更有效,并且使用这种方法的真正好处。
  3. 转换器用于将值从一种类型转换为另一种类型(从1,必需,也是一个问题)
  4. 可以像吸气剂和制定者一样行事。
  5. 我正在努力解决的问题是编写链接和转换为任何类型的能力。以下代码适用于较小的更改(将模板化的Chain函数转换为非模板化版本,并在Chain<F>函数中将Chain更改为SetLink。问题是,没有正确调用链接。

    这个类几乎可以工作(它确实可以编译运行但是没有按预期工作。如果没有上面的更改,绑定函数永远不会调用。它只是测试代码而没有正确编码(请不要评论使用静态计数器,它只是一个临时修复。)链和链接元素是至关重要的方面。

    Chain简单地假设转换并更新属性的值,然后将它(或可能是原始值)传递给下一个属性。这种情况一直持续到一个人回到原来的财产,在这种情况下它会终止。

    #include <iostream>
    #include <string>
    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    
    using namespace std;
    
    
    
    static int iLCount = 1;
    template <typename T>
    class LinkableProperty
    {
        public:
            std::string Name;       
            boost::function<void(T)> Link;
    
            T Value;
    
            template<typename F>
            void Chain(F val)
            {
                Value = val;
                std::cout << this->Name << " - " << this << ", " << &Link << ", " << val << " ! " << this->Value << " - " << "\n";
                if (--iLCount < 0) return;
                if (!Link.empty()) Link(Value);
            }
    
    
            LinkableProperty() { Link = NULL; Value = T(); Name = "Level " + std::to_string(iLCount++); };
    
            void operator =(T value) { Value = value; }
    
            template<typename F> void SetLink(LinkableProperty<F> &p)
            {           
                Link = boost::bind(&LinkableProperty<F>::template Chain<F>, &p, _1);
            }
    
            void operator ()()
            {
                if (!Link.empty()) Link(Value);
            }
    
    };
    
    
    
    int main()
    {
    
        LinkableProperty<unsigned short> L1;
        LinkableProperty<double> L2;
    
        L2.SetLink(L1);
        L1.SetLink(L2);
    
        L1 = 1;
        L2 = 1.1;
    
        L1();
    
        cout << "----------\n" << L1.Value << ", " << L2.Value << endl;     
        getchar();
        return 0;
    }
    

1 个答案:

答案 0 :(得分:1)

问题很可能源于此:

template<typename F> void SetLink(LinkableProperty<F> p)

您传递的是原始财产的副本。改变这个以接受引用(或指针),你可能会有更好的运气。例如:

template<typename F>
void SetLink(LinkableProperty<F>* p)
{           
  Link = boost::bind(&LinkableProperty<F>::template Chain<F>, p, _1);
}

应该按预期工作......

编辑:已更新,以显示如何在转化过程中保留类型:

template <typename FT, typename TT>
TT convert(FT v)
{
  return v; // default implicit conversion
}

template<>
double convert(unsigned short v)
{
  std::cout << "us->d" << std::endl;
  return static_cast<double>(v);
}

template<>
unsigned short convert(double v)
{
  std::cout << "d->us" << std::endl;
  return static_cast<unsigned short>(v);
}

static int iLCount = 1;
template <typename T>
class LinkableProperty
{
  template <typename U>
  struct _vref
  {
    typedef U vt;
    _vref(vt& v) : _ref(v) {}
    U& _ref;
  };
    public:
        std::string Name;       
        boost::function<void(_vref<T>)> Link;

        T Value;

        template<typename F>
        void Chain(F const& val)
        {
            Value = convert<typename F::vt, T>(val._ref);
            std::cout << this->Name << " - " << this << ", " << &Link << ", " << val._ref << " ! " << this->Value << " - " << "\n";
            if (--iLCount < 0) return;
            if (!Link.empty()) Link(Value);
        }


        LinkableProperty() { Link = NULL; Value = T(); Name = "Level " + std::to_string(iLCount++); };

        void operator =(T value) { Value = value; }

        template<typename F>
        void SetLink(LinkableProperty<F>* p)
        {           
            Link = boost::bind(&LinkableProperty<F>::template Chain<_vref<T>>, p, _1);
        }

        void operator ()()
        {
            if (!Link.empty()) Link(_vref<T>(Value));
        }

};



int main()
{

    LinkableProperty<unsigned short> L1;
    LinkableProperty<double> L2;

    L2.SetLink(&L1);
    L1.SetLink(&L2);

    L1 = 1;
    L2 = 1.1;

    L1();

    cout << "----------\n" << L1.Value << ", " << L2.Value << endl;     
    getchar();
    return 0;
}

注意:有一些链接错误意味着更新会触发超过必要的次数 - 您应该检查...