简体   繁体   English

在对象中传递函数和运算符

[英]Passing function and operator calls in object

I am wanting to make a class which allows me to lock an object from being modified. 我想创建一个类,使我可以锁定对象,以免被修改。 It would essentially be a template with a boolean specifying the lock state. 它本质上是一个带有布尔值的模板,用于指定锁定状态。 Since it is a template, I won't know all the methods that can be called on the internal object, so I need a method to pass calls through... 因为它是模板,所以我不知道可以在内部对象上调用的所有方法,所以我需要一个方法来传递调用。

template<class T>
class const_lock
{
  public:
  const_lock() : my_lock(false) {}
  void set_const_lock(bool state) {my_lock = state;}

  // HOW TO IMPLEMENT SOMETHING LIKE THESE????
  //
  template<typename...Args >
  auto operatorANY_OPERATOR (Args...args)
 {
    if(my_lock != false)
       throw std::exception("Objected locked to modification");
    return my_value.ANY_OPERATOR(args);
 }

  template<typename...Args >
  auto operatorANY_CONST_OPERATOR (Args...args) const
 {
    return my_value.ANY_CONST_OPERATOR(args);
 }

  template<typename...Args >
  auto ANY_METHOD(Args...args)
 {
    if(my_lock != false)
       throw std::exception("Objected locked to modification");
    return my_value.ANY_METHOD(args);
 }

  template<typename...Args >
  auto ANY_CONST_METHOD(Args...args) const
 {
    return my_value.ANY_CONST_METHOD(args);
 }

  private:
    bool my_lock;
    T my_value;
}

int main()
{
  const_lock<std::vector<int>> v;
  v.push_back(5);
  v.push_back(7);
  v.set_const_lock(true);
  v.push_back(9); // fails compilation
  std::cout << v.at(1) << std::endl; // ok
}

Any help would be appreciated. 任何帮助,将不胜感激。 Thanks! 谢谢!

Edit: changed static assert to throw and exception 编辑:将静态断言更改为throw和exception

What you're trying to do looks rather difficult, but more importantly is over-complicated and unnecessary for what you're trying to do. 您尝试做的事情看起来相当困难,但是更重要的是,对于您尝试做的事情来说过于复杂和不必要。

Essentially what you're trying to do (correct me if I'm wrong) is create a compile time check of whether you are supposed to able to modify an object at a given time. 从本质上讲,您要尝试进行的操作(如果我错了,请纠正我)是创建编译时检查,以检查是否应该在给定的时间修改对象。 However, c++ already has a built in way of doing this. 但是,c ++已经具有执行此操作的内置方法。 Simply declare or pass your object as const or const&, and the compiler will not allow you to modify non-mutable parts of the object. 只需将您的对象声明为const或const&即可,编译器将不允许您修改对象的非可变部分。 When you want to be able to modify it pass it without const. 当您希望能够对其进行修改时,可以不带const进行传递。 You can even cast it from const& to regular & when you want to go from code where you can't modify it directly to code where you can, though I don't recommend it. 您甚至可以将其从const&强制转换为常规&,而您想从无法直接修改它的代码转到可以的代码中,尽管我不建议这样做。

edit: just saw a comment on the question about no reference arrays. 编辑:刚刚看到关于没有引用数组的问题的评论。 Don't worry about that! 不用担心! The standard library has support for reference wrappers which allow you to essentially store references in arrays or anywhere else. 标准库支持引用包装,使您可以将引用本质上存储在数组或其他任何位置。

You can make a generic wrapper class that you can forward the function to using a lambda that captures a reference to the internal member. 您可以创建一个通用包装器类,然后将其转发给使用捕获内部成员引用的lambda函数。 In this example I am just using an if statement to check if it is "locked" and if it is then we just modify a copy. 在这个例子中,我只是使用一个if语句来检查它是否被“锁定”,如果是,那么我们只是修改一个副本。

template<class T>
class const_lock
{
private:
    bool my_lock;
    mutable T my_value;
public:
    const_lock() : my_lock(false) {}
    void set_const_lock() { my_lock = true; }


    template<typename F>
    auto operator()(F f) const -> decltype(f(my_value))
    {
        if (my_lock)
        {
            T temp{my_value};  // make a copy
            return f(temp);
        }
        else 
            return f(my_value); // modify wrraped value
    }
};

int main()
{
    const_lock<std::string> cl;
    cl([](std::string& s) {
        s = "foobar";
    });
    cl([](std::string& s) {
        std::cout << s << std::endl;
    });
    cl.set_const_lock();
    cl([](std::string& s) {
        s = "we should still be foobar";
    });
    cl([](std::string& s) {
        std::cout << s;
    });
}

This is completely unimplementable. 这是完全无法实现的。 A trivial modification of your source code shows why this won't work. 对源代码进行小小的修改就可以说明为什么它不起作用。

int main()
{
  const_lock<std::vector<int>> v;
  v.push_back(5);
  v.push_back(7);
  if (rand() % 2)
      v.set_const_lock(true);
  v.push_back(9); // fails compilation
  std::cout << v.at(1) << std::endl; // ok
}

You need to completely rethink your approach. 您需要完全重新考虑您的方法。

Below is an example illustrating what I would be trying to protect against 下面是一个示例,说明了我将要防范的内容

  class Node
  {
    public:
      Node(int id) : my_id(id) {}
      // . . . 
      int id() {return my_id;}

    private:
      int my_id;
      // . . .
  };

  class Grid
  {
    public:
      Grid() {}
      // . . . 

      void associate(Node* n) { my_nodes.push_back(n); }

    private:
      // . . .
      std::vector<Node*> my_nodes;
  };

  Node* find(std::vector<Node>& Nodes, int ID)
  {
    for(auto i=Nodes.begin(); i!=Nodes.end(); ++i)
    {
      if (i->id() == ID)
      {
        return &*i;
      }
    }
  }

  main()
  {
    std::vector<Node> Nodes;
    // fill Nodes with data


    Grid Array;
    Array.associate( find(Nodes,14325) );
    Array.associate( find(Nodes,51384) );
    Array.associate( find(Nodes,321684) );

    // . . .
    Nodes.push_back(Node(21616)); // this can invalidate my pointers in Array

  }

If I was able to make my Nodes vairable be 如果我能够使我的节点可变

 const_lock<std::vector<Node>> Nodes;

then call 然后打电话

 Nodes.set_const_lock(true);

after populating the data, I wouldn't need to worry about my pointers in Array getting messed up. 填充数据后,无需担心Array中的指针弄乱了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM