如何将模板类放入args包本身?

How to put template class into args pack itself?

提问人:Ariz 提问时间:11/4/2023 最后编辑:user12002570Ariz 更新时间:11/4/2023 访问量:69

问:

我有如下模板类:

template<typename T>
class A;

template<typename ...Args>
class A<void(Args...)> {
public:
    void(*callback)(Args....);

    void foo(Args... args) {
        /* stuffs */
    }
};

是否可以在定义指定类时放入 Args 包本身,例如:?
使类类似于:
A<void(Args...)>A<void(A<...>, /* other args */)>

class B {
public:
    void(*callback)(const B&, /* other args */);

    void foo(const B&, /* other args */) {
        /* stuffs */
    }
};

我可以通过使用 like 来使其工作,然后转换回函数中的原始函数。只是想问一下是否可能以及如何去做,而不使用.void*A<void(void*, /* other args */>void*

C++ 模板

评论


答:

0赞 Pepijn Kramer 11/4/2023 #1

我会让 lambda/std::function 组合完成繁重的工作。 这可能会导致一些开销,但代码变得更易于维护,如下所示:

#include <functional>
#include <iostream>
#include <string>
#include <type_traits>

template<typename... args_t>
class A
{
public:
    template<typename fn_t> 
    auto register_callback(fn_t fn) // possibly constrain here (using SFINAE or concept)
    {
        m_callback = fn;
    }

    void func_with_callback(args_t&&... args)
    {
        m_callback(std::forward<args_t>(args)...);
    }

private:
    std::function<void(const args_t&...)> m_callback;
};

int main()
{
    std::string hello{"Hello"};
    A<std::string> a;

    // use lambdas to capture all the variables you need.
    a.register_callback([=](const std::string& name){ std::cout << hello << " " << name; });
    a.func_with_callback("Dave");

    return 0;
}

评论

0赞 Ariz 11/4/2023
很抱歉让你对我的问题感到困惑,课堂上的字段只是一个例子,它可能会有所不同。但我需要的是模板中的列表必须与类字段中的列表相同,并且必须与列表中的列表相同,并且本身在列表中一次。ArgsArgsArgsA<...>::foo()A<...>ArgArgs
0赞 Pepijn Kramer 11/4/2023
没问题;)我花了几分钟来写这个
0赞 user12002570 11/4/2023 #2

是否可以在定义指定类时放入 Args 包本身,例如:?A<void(Args...)>A<void(A<...>, /* other args */)>

是的,如下图所示。请注意 和 的定义中添加的第一个参数。const A<void(Args...)>&callbackfoo

template<typename T>
class A;

template<typename ...Args>
class A<void(Args...)> { 
public:
//------------------vvvvvvvvvvvvvvvvvvvvv-------------->added this first argument
    void(*callback)(const A<void(Args...)>&, Args...);
//-----------vvvvvvvvvvvvvvvvvvvvv--------------------->added this first argument
    void foo(const A<void(Args...)>&,Args... args) {  
        
    }
}; 
void func(double, int)
{

}
int main()
{ 
      
    A<decltype(func)> a;
}  

现场演示

以上将导致您想要的类类型的实例化

template<>
class A<void (double, int)>
{
  
  public: 
  void (*callback)(const A<void (double, int)> &, double, int);
  inline void foo(const A<void (double, int)> &, double __args1, int __args2);
  
  // inline A() noexcept = default;
};

请注意,使用注入的类名,只需在参数列表中写入即可使代码更具可读性。const A&

template<typename ...Args>
class A<void(Args...)> { 
public:
//------------------------v---------------->injected class name
    void(*callback)(const A&, Args...);
//----------------------------------------->injected class name
    void foo(const A&,Args... args) {  
        
    }
};

带有注入类名的演示

评论

0赞 Ariz 11/4/2023
谢谢你的回答。我也明白了。因为可以用在问题以外的情况下一次,所以我需要的是模板中的列表必须与类字段中的列表相同,并且必须与中的列表相同。A<void(Args...)>ArgsArgsArgsA<...>::foo()
0赞 Jarod42 11/4/2023
没有注入的类名,甚至就足够了。void (*callback)(const A&, double, int);
0赞 user12002570 11/4/2023
@Ariz 不清楚你在问什么/说什么。请随时为您提出一个新的单独问题,跟进问题和新要求。不应在问题已经有答案后添加新要求,以致使答案无效。
0赞 user12002570 11/4/2023
@Jarod42 啊,这将使代码更具可读性。更新。