簡體   English   中英

從名稱的類型和字符串返回指針

[英]Return pointer from type and string of name

如何從其名稱的字符串中返回(已知的)指向已知類型的指針? 假設我創建了一些名為map1 map<string, double>和一些名為vec1 vector<string> 我想編寫一個函數,該函數將從"map1"返回map1"map1" vec1 "vec1" (以及另外一個參數,用於指定每個參數的各自類型)。

這可能嗎?

我的最終目標是獲得一個以QString形式命名的QWidget ,因為我正在使用大量的QWidget ,盡管答案應該與框架無關,對嗎?

您需要執行某種動態調度。 為此,您可以簡單地從您的建議開始:

enum class types { A = 0, B = 1 };
void (*handlers[])(void*) = { &HandleA, &HandleB };

::std::unordered_map<::std::string, ::std::tuple<types, void*>> registry;

現在剩下的就是執行查找了:

void lookup(::std::string const& name)
{
    auto& t = registry.at(name);
    handlers[static_cast<size_t>(::std::get<0>(t))](::std::get<1>(t));
}

為處理程序自動變元

這些處理程序都接受一個void*類型的參數-這可以通過添加一些模板魔術來解決:

template<typename T, void(*f)(T*)>
void handle(void* arg)
{
    f(static_cast<T*>(arg));
}

void (*handlers[])(void*) = { &handle<A, &HandleA>, &handle<B, &HandleB> };

現在,原型是例如void HandleA(A*)

簡單地將對象添加到注冊表

使用當前代碼,您可以像這樣將對象添加到注冊表中:

A a;
registry.emplace("A #1", ::std::make_tuple(types::A, &a));

雖然這很完美,但我們想做一些更優雅的事情。 讓我們首先將enum class types更改為某種東西,該類型也知道我們希望代表的類型:

template<typename T> struct types;
template<> struct types<A> { static const size_t id = 0; };
template<> struct types<B> { static const size_t id = 1; };

當然,現在我們需要修復注冊表類型:

::std::unordered_map<::std::string, ::std::tuple<size_t, void*>> registry;

最后,我們可以提供一個簡單的插入函數:

template<typename T>
void insert(::std::string const& name, T* object)
{
    registry.emplace(name, ::std::make_tuple(types<T>::id, static_cast<void*>(object)));
}

最終用法示例

A a;
insert("A #1", &a);
lookup("A #1");

元對象系統已經處理了這個問題,所以答案將是特定於框架的,因為您通常需要代碼生成器來獲取有關C ++類型的元數據,而這些元數據在其他情況下是不可用的。

QLineEdit * ed = ...;
ed->setObjectName("myObject");

... elsewhere in the code

foreach(QWidget * w, QCoreApplication::allWidgets()) {
  // Lookup by name
  if (w->objectName() == "myObject") {
    ...
  }
  // Lookup by type
  if (qobject_cast<QLineEdit*>(w)) {
    ...
  }
}

如果您想加快查找速度,並且這些對象具有唯一的名稱:

class Widgets {
  typedef QMap<QString, QPointer<QWidget>> Data;
  mutable Data m_map;
public:
  Widgets() {
    foreach(QWidget * w, QCoreApplication::allWidgets()) {
      if (w->objectName().isEmpty()) continue;
      m_map.insert(w->objectName(), w);
    }
  }
  QWidget * lookupWidget(const QString & name) const {
    Data::iterator it = m_map.find(name);
    if (it == m_map.end()) return nullptr;
    QWidget * w = it->data();
    if (!w) m_map.erase(it); // The widget doesn't exist anymore
    return w;
  }
  template <typename T> T * lookup(const QString & name) const {
    return qobject_cast<T*>(lookupWidget(name));
  }
  void setName(QWidget * w, const QString & name) {
    Q_ASSERT(! name.isEmpty());
    w->setObjectName(name);
    m_map.insert(name, w);
  }
};

在您的代碼中,使用widgets->setName()代替setObjectName

如果要同時按名稱和類型查找,則只要所有名稱都屬於不同類型,就可以使用重復名稱:

class Widgets2 {
  typedef QPair<QString, QString> Key;
  typedef QMap<Key, QPointer<QWidget>> Data;
  mutable Data m_map;
  static Key keyFor(QWidget * w) {
    return qMakePair(w->objectName(),
      QString::fromLatin1(w->metaObject()->className()));
public:
  Widgets2() {
    foreach(QWidget * w, QCoreApplication::allWidgets()) {
      if (w->objectName().isEmpty()) continue;
      m_map.insert(keyFor(w), w);
    }
  }
  QWidget * lookupWidget(const QString & name, const QString & type) const {
    Data::iterator it = m_map.find(qMakePair(name, type));
    if (it == m_map.end()) return nullptr;
    QWidget * w = it->data();
    if (!w) m_map.erase(it); // The widget doesn't exist anymore
    return w;
  }
  template <typename T> T * lookup(const QString & name) const 
  {
    return qobject_cast<T*>(lookupWidget(name, 
      QString::fromLatin1(T::staticMetaObject.className())));
  }
  void setName(QWidget * w, const QString & name) {
    Q_ASSERT(! name.isEmpty());
    w->setObjectName(name);
    m_map.insert(keyFor(w), w);
  }
};

查找工作如下:

widgets2->lookup<QLineEdit>("myObject")->setText("foo");

我利用QObjectQPointer使小部件注冊表對於刪除小部件而言是安全的-您永遠都不會得到懸掛的指針。

如果願意,也可以跟蹤對象名稱的更改: QObject發出objectNameChanged信號。

當然,所有這些都是圍繞代碼損壞的設計的可怕駭客。 您需要這樣做的事實意味着您正在緊密地將業務邏輯和GUI耦合在一起。 您應該使用某種模型視圖架構。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM