使用外部函数获取和设置嵌套结构的值

时间:2019-01-03 18:06:03

标签: c++ c++11 struct

我正面临以下问题。我有a map的受保护数据结构<ID , Object>。只有一个映射数据结构,并且多个线程可能想使用set从映射中getID的值。 Object可以嵌套,如下面的示例代码所示。

#include <iostream>
#include <map>
#include <algorithm>
#include <mutex>
using namespace std;
struct C {
    int r;
    char s;
};
struct B {
    int p;
    char q;
    C c;
};
struct A {
    int x;
    int y;
    B b;
    char z;
};
/*
    A
    L__ x
    |
    L__ y
    |
    L__ B
        L__p
        |
        L__q
        |
        L__C
            L__r
            |
            L__s

*/
/*  the follwing is the
    data structure to store objects of of type A 
    corresponding to an ID (int)
*/
map<int,A> Map;
mutex m;

/*  Follwing are the desired 
    api's to set and get values from the Map 
    Locks are also required to handle concurrency
*/
void getValueFromMap(int id,/* what to pass ?? */) {
    m.lock();

    /* code to get the value of the specified varible */

    m.unlock();
}
void setValueInMap(int id,/* what to pass ?? */) {
    m.lock();

    /* code to set the new value to the specified variable */

    m.unlock(); 
}
int main() {
    /* lets suppose Map has some A type objects already */
    int id = 4;
    /* assume I want to change the information (value of p) of  id = 4*/
    /* instead of doing the following */
    m.lock();
    Map[id].b.p = 12; /*update to some value */
    m.unlock();
    /* what I need the follwing */
    setValueInMap(4,/* what_to_change , what_is_the_new_value etc .. */);

    /*similarly */

    /*if I want get the value of s */
    int s;
    m.lock();
    getValueFromMap(id,/* what_to_get,placeholder (for example &s) */);
    m.unlock();
}

我想使用函数对api的{​​{1}}和setValueInMap的值进行set个调用(例如,get具有固定数量的参数)呼叫和所有互斥工作将仅在这些map呼叫内发生。尽管我仅展示了一个通用集合函数来设置api的所有类型的成员变量,但不必如此(更多api函数调用没有问题)。

如何实施?

谢谢!

4 个答案:

答案 0 :(得分:5)

如何使通用函数作用于地图:

std::map<int, A> Map;
std::mutex m;

template <typename F>
auto ActOnMap(F&& f) -> decltype(f(Map)) {
    std::lock_guard<std::mutex> locker(m);
    return f(Map);
}

(注意:您可能应该创建一个用于构造该类的类,并隐藏对mapmutex的直接访问。)

然后:

/* lets suppose Map has some A type objects already */
int id = 4;
/* assume I want to change the information (value of p) of  id = 4*/
ActOnMap([id](std::map<int, A>&m){ m[id].b.p = 12;});

/*similarly */

/*if I want get the value of s */
int s = ActOnMap([id](std::map<int, A>&m){ return m[id].b.c.s;});

答案 1 :(得分:3)

主要问题是如何将所谓的“占位符”编码到C ++类型系统中。要选择:

  • 普通索引(0 -> A.x3 -> B.q等)和一些硬编码的switch语句(非常脆弱,不建议使用)。

  • 相同,但是带有枚举而不是索引。没有比上面更好的了。

  • 成员变量指针。这将变得非常尴尬,尤其是由于nested structure

  • 功能。您可以为每个(嵌套的)成员编写访问函数,并将函数指针传递给这些成员(或函子,例如lambda)。像这样:

    void setBp(A& a, int value) { a.b.p = value; }
    // etc.
    
    template<typename T, typename SetterFunc>
    setValueInMap(int key, SetterFunc setterFunc, T value) {
      m.lock();
      setterFunc(Map[id], value);
      m.unlock();
    }
    
    // Usage
    setValueInMap(4, setBp, 12);
    

请注意,这些方法都不是非常漂亮的。完全没有我会考虑更改底层设计,嵌套结构确实是此问题的根源。

答案 2 :(得分:1)

也许您可以选择RapidJson方法或基于if的方法(不太优雅):

(...)

void* getValueFromMap(int id, char structure, string item_name) {
    m.lock();

    if(structure == 'C') {
         if(item_name.compare("r") == 0) {
              return (void*) Map[id].B.C.r;
         } else if(...

    } else if(...

    m.unlock();
}
void setValueInMap(int id, char structure, string item_name, void* item) {
    m.lock();

    if(structure == 'C') {
         if(item_name.compare("r") == 0) {
              Map[id].B.C.r = (int) item;
         } else if(...

    } else if(...


    m.unlock(); 
}

int main() {
    int r;
    r = (int) getValueFromMap(4,'C',"r");

    setValueInMap(5,'C',"r",(void*) r);
}

免责声明::我没有编译这段代码,所以它可能有错误。

答案 3 :(得分:1)

您可以轻松生成用于访问嵌套成员的lambda或函数的一种方法是编写函数或脚本以使用脚本语言生成它们。

# Ruby
def dig_lambda(*members)
  dig = "Map[id].#{members.join '.'}"  
  puts "[&]() -> decltype(#{dig}) {return #{dig};}" 
end

# prints [&]() -> decltype(Map[id].b.c.r) {return Map[id].b.c.r;}
dig_lambda %w[b c r]