I am trying to use perfect forwarding with parameter pack definitions made for a whole class, not just for the specific function. example:
#include <tuple>
template<typename Ret, typename... Params>
class Example {
public:
Ret call(Params&&... data)
{
}
template <typename ...TParams> Ret
call1(TParams&&... data)
{
}
private:
};
int main() {
Example<void, int, short> example;
int i = 32;
//example.call(i, 0);
example.call1(i, 0);
}
But the compiler makes a difference between call and call1. I thought that both examples shall work. If you uncomment "call" the compiler gives the error:
" rvalue reference to type 'int' cannot bind to lvalue of type 'int'"
My problem exactly: I wanted to create a call-system where you can derive and override the call function. But you can't override templated functions.
If I use it without the Rvalue-References it's working fine. But since my architecture has at least one deeper call since the calling class is just derived by another class which has the same template with that parameter pack which then is std::forwarded. That's where I came to the topic of perfect forwarding, which is not useable this way.
So the idea was to use it like this:
#include <tuple>
template<typename Ret, typename... Params>
class Base {
public:
Ret call(Params&&... data)
{
}
};
template<typename Ret, typename... Params>
class Derived : public Base<Ret, Params...> {
public:
Ret call(Params&&... data)
{
Base<Ret, Params...>::call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
};
int main() {
Derived<void, int, short> MyDerived;
int i = 32;
//MyDerived.call(i, 0);
MyDerived.call1(i, 0);
}
But of course this does not work.
So using it without "&&" does work but as said with the additional stack-memory per deeper call.
#include <tuple>
template<typename Ret, typename... Params>
class Base {
public:
Ret call(Params... data)
{
}
};
template<typename Ret, typename... Params>
class Derived : public Base<Ret, Params...> {
public:
Ret call(Params... data)
{
Base<Ret, Params...>::call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
};
int main() {
Derived<void, int, short> MyDerived;
int i = 32;
MyDerived.call(i, 0);
MyDerived.call1(i, 0);
}
It works if you pass the parameters by std::move :
#include <tuple>
template<typename Ret, typename... Params>
class Base {
public:
Ret call(Params&&... data)
{
}
};
template<typename Ret, typename... Params>
class Derived : public Base<Ret, Params...> {
public:
Ret call(Params&&... data)
{
Base<Ret, Params...>::call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
};
int main() {
Derived<void, int, short> MyDerived;
int i = 32;
MyDerived.call(std::move(i), std::move(0));
MyDerived.call1(i, 0);
}
Besides this produces a load of code, I do not want the Users of my API to always use std::move, just pass the parameters as normal.
To complexify a bit, an additional case which shall also work the same behaviour but with a composit instead of an inheritance. This leads definetely to an additional stack allocation of the pack expansion for the call of the Composit, which I want to optimize, since this is not needed:
#include <tuple>
template<typename Ret, typename... Params>
class Composit {
public:
Ret call(Params&&... data)
{
}
};
template<typename Ret, typename... Params>
class MainClass {
public:
MainClass() : callee(new Composit<Ret, Params...>())
{}
Ret call(Params&&... data)
{
callee->call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
Composit<Ret, Params...>* callee;
};
int main() {
MainClass<void, int, short> MyClass;
int i = 32;
MyClass.call(std::move(i), std::move(0));
//MyClass.call1(i, 0);
}
Is there any solution to solve this problem without std::move?
Code was run on a clang-compiler: https://godbolt.org/z/vecsqM9sY You can simply copy the examples inside.