简体   繁体   中英

Variadic Template for qobject_cast via parent()

gurus and template-experts, I need your help ...

I am currently looking for a solution on checking a QObject's parent hierarchy. I have a custom QDialog with the following hierarchy (parent to child):

QDockWidget
> CustomDockArea
  > QMainWindow
    > QDockWidget
      > CustomDialog

Within the CustomDialog class, I want to check if the dialog's hierarchy matches this example, so I checked if this is accomplishable with a variadic template, for example:

assert(qobject_cast_parent<QDockWidget*, QMainWindow*, CustomDockArea*, QDockWidget*>(this));

and I have come up with something like this:

template <class T, class... Ts>
inline T qobject_cast_parent(QObject* root)
{
    if (root)
    {
        if (sizeof...(Ts) == 0)
        {
            return qobject_cast<T>(root->parent());
        }
        else
        {
            return qobject_cast_parent<Ts...>(root->parent());
        }
    }
    else
    {
        return nullptr;
    }
}

However, there a few problems: I need the last parameter of the parameter pack as being the return type of the function, in our example QDockWidget*. I could take the first parameter as being the return type, but this would make the template call a little bit cumbersome. However, even if that would be solved, I think there is still a problem with the way the parameter pack is "unrolled" and now I got a little bit unsure if my template-approach is even feasible for the original problem. Maybe you can give me some hints. Thanks in advance!!!

With c++14, you may simply use auto as return type:

template <class T>
T* qobject_cast_parent(QObject* root)
{
    return root
        ? qobject_cast<T*>(root->parent())
        : nullptr;
}

template <class T, class T2, class... Ts>
auto qobject_cast_parent(QObject* root)
//-> typename Last<T2, Ts...>::type /* In c++11, you have to create this traits */
{
    return root
        ? qobject_cast_parent<T2, Ts...>(qobject_cast<T*>(root->parent()))
        : nullptr;
}

As I don't have your complete code, I can only confirm that the following compiles, but could not test it. I'm sure you can test it for me though, let me know if this doesn't work or if I misunderstood your problem.

#include <QtCore/QObject>
#include <cassert>
#include <type_traits>

// This ends the recursion with the actual qobject_cast.
template <class T, class U>
inline U *qobject_cast_parent(T* root)
{
  // Make sure everything's a QObject, clear message if not.
  static_assert(std::is_base_of<QObject, T>::value, "Object must be a QObject");

  if (root)
  {
    return qobject_cast<U *>(root->parent());
  }
  else
  {
    return nullptr;
  }
}

template <class T, class U, class... Us>
inline U *qobject_cast_parent(T* root)
{
  // Make sure everything's a QObject, clear message if not.
  static_assert(std::is_base_of<QObject, T>::value, "Object must be a QObject");

  if (root)
  {
    return qobject_cast_parent<U, Us...>(qobject_cast<U *>(root->parent()))
  }
  else
  {
    return nullptr;
  }
}

So the template parameters are ordered from child to parent, and you'll be forced to specify the innermost type as well. So I think your assert example would look like this (again, untested, let me know how it works out):

assert(qobject_cast_parent<CustomDialog,
                           QDockWidget,
                           QMainWindow,
                           CustomDockArea,
                           QDockWidget>(this));

Edit : For sake of completeness, you were also asking about a way to get to the type of last parameter of a parameter pack. You could use something like this:

template <typename T, typename... Ts>
struct Last
{
  typedef typename Last<Ts...>::type type;
};

template <typename T>
struct Last<T>
{
  typedef T type;
};

int main()
{
  // For example, this gives std::string:
  Last<int, float, char, std::string>::type foo = "bar";
  return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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