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