C++从对象获取模板类型

dffbzjpn  于 9个月前  发布在  其他
关注(0)|答案(2)|浏览(135)

我目前正在开发一个GUI应用程序。我的GUI应用程序类是一个单例,它依赖于一个模板化的Mutex和一个模板化的事件处理任务。
//GUIApplication.hpp

#include <cassert>
template<typename Task_T, typename Mutex_T>
class GUIApplication
{
  public:
    GUIApplication()
    {
      m_pInstance = this;
    }
    static Mutex_T& getMutexInstance()
    {
      assert(nullptr != m_pInstance);
      return m_pInstance->m_GuiMutex;
    }
  private:
    inline static GUIApplication<Task_T, Mutex_T>* m_pInstance = nullptr;

    Task_T m_eventTask;
    
    Mutex_T m_GuiMutex;
};

字符串
现在我有一些其他的类需要在做事情之前锁定互斥锁。但是我不想用这些其他的类制作模板。有没有一种方法可以从GUIApplication的当前示例中“派生”或“保存”模板类型。

//Foo.hpp
class Foo
{
  public:
  Foo();
};

//Foo.cpp
#include <mutex>
Foo::Foo()
{
  //here (obviously) the template auto argument deduction fails
  auto lock = std::scoped_lock(GUIApplication::getMutexInstance());
  //do stuff here....
}


Thx guys for your help:)

4uqofj5v

4uqofj5v1#

显然,您无法避免为GUIApplication指定模板参数,因此GUIApplication::getMutexInstance无法工作。

(1)从别名构建GUIApplication

但是,巧妙地使用别名可以帮助您避免重复:

using Mutex = std::mutex;
using Task = MyTask;
using App = GUIApplication<Task, Mutex>;

auto lock = std::scoped_lock(App::getMutexInstance());

字符串

(2)提取GUIApplication的别名

类似地,您可以向GUIApplication添加别名成员,以便更轻松地从中提取模板参数:

template<typename Task_T, typename Mutex_T>
class GUIApplication {
  public:
    using Task = Task_T;
    using Mutex = Mutex_T;
  // ...
};

// ...
using App = GUIApplication<Task, Mutex>;
using Task = App::Task;
using Mutex = App::Mutex;


您经常在标准库中看到这种模式,例如std::string::size_typestd::vector::value_type等。

liwlm1x9

liwlm1x92#

你可以实现一个自定义的类型trait来通过索引获取模板参数。
我已经做了一个依赖于std::tuplestd::tuple_element_t的快速实现,但是你也可以在没有这些的情况下正确地实现它(如果需要的话)。

#include <tuple>
#include <type_traits>

template <int I, typename T>
struct template_param;

template <std::size_t I, template <typename...> typename T, typename... TArgs>
struct template_param<I, T<TArgs...>>
{
    using type = std::remove_pointer_t<std::tuple_element_t<I, std::tuple<TArgs*...>>>;
};

template <int I, typename T>
using template_param_t = template_param<I, T>::type;

字符串
然后在代码中使用它如下:

#include <type_traits>

template <typename TTask, typename TMutex>
struct GuiApplication
{
};

struct Task;
struct Mutex;

int main()
{
    auto app = GuiApplication<Task, Mutex>{};
    static_assert(std::is_same_v<template_param_t<0, decltype(app)>, Task>);
    static_assert(std::is_same_v<template_param_t<1, decltype(app)>, Mutex>);
}


这并不能修复编译失败的示例,它只是一种获取模板参数的替代方法。
为了真正修复你的错误,我更喜欢GuiApplication的别名,就像Jan Schultke建议的那样,让编译器推导出所有的东西。

相关问题