Home > Enterprise >  How to put template class into args pack itself?
How to put template class into args pack itself?

Time:11-05

I have template class like below:

template<typename T>
class A;

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

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

Is it possible put A<void(Args...)> in Args pack itself while define specified class, like: A<void(A<...>, /* other args */)> ?
Make class something similar to:

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

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

I can make it work by using void* like A<void(void*, /* other args */>, then cast back to the original one inside the function. Just want to ask if it possible and how to do it, without using void*.

CodePudding user response:

I would let lambda/std::function combo do the heavy lifting. It may result in a bit of overhead but the code becomes more maintainable and would look something like this:

#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;
}

CodePudding user response:

Is it possible put A<void(Args...)> in Args pack itself while define specified class, like: A<void(A<...>, /* other args */)> ?

Yes there is, as shown below. Note the added first argument const A<void(Args...)>& in the definitions of callback and foo.

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;
}  

Live demo

The above will result in an instantiation of a class-type like you want:

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;
};

Note that with injected class name you can just write const A& in the parameter list to make the code more readable.

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) {  
        
    }
};

Demo with injected class name

  • Related