I am trying to use static polymorphism like in the simple example shown below.
#include <iostream>
template <typename Derived>
struct Base
{
decltype(auto) foo() { return static_cast<Derived&>(*this).foo(); }
};
struct Derived : Base<Derived>
{
void foo() { std::cout << "Derived" << std::endl; }
};
template <typename T>
struct Traits;
template <typename T>
struct Traits<Base<T>>
{
using Derived = T;
};
template <typename T>
struct Object
{
template <typename U>
Object(U&& data) : m_data(std::forward<U>(data)) {}
T m_data;
};
template <typename T>
decltype(auto) polymorphicCall(T&& obj)
{
using Derived = typename Traits<std::decay_t<T>>::Derived;
return Object<Derived>(static_cast<Derived&>(obj));
}
int main()
{
Derived d;
polymorphicCall(d);
return 0;
}
The problem is that T
in polymorphicCall
is deduced as Derived
, this way anything can be passed to that function, even int
. Is there a way to only accept Base<Derived>
types?
I tried using a forwarding reference and an enable_if
on the template parameter, but then i can't deduce the Base
s template parameter.
Is there any way to use both forwarding references and static polymorphism?
EDIT: Updated the code example to include the actual forwarding reference and how a try to use it.
The error shown is: "error: invalid use of incomplete type 'struct Traits'"
If the goal is just to limit the use of polymorphicCall
to types derived from Base
you can do that with a static_assert
and a type trait.
#include <iostream>
template <typename Derived>
struct Base
{
decltype(auto) foo() { return static_cast<Derived&>(*this).foo(); }
};
struct Derived : Base<Derived>
{
void foo() { std::cout << "Derived" << std::endl; }
};
template <typename T, typename = void>
struct IsDerivedFromBase : std::false_type {};
template <typename T>
struct IsDerivedFromBase<T, std::enable_if_t<std::is_base_of_v<Base<T>, T>>> : std::true_type {};
template <typename T>
struct Object
{
template <typename U>
Object(U&& data) : m_data(std::forward<U>(data)) {}
T m_data;
};
template <typename T>
decltype(auto) polymorphicCall(T&& obj)
{
using Derived = std::remove_cvref_t<T>;
static_assert(IsDerivedFromBase<Derived>::value);
return Object<Derived>(std::forward<T>(obj));
}
int main()
{
Derived d;
polymorphicCall(d);
int i;
//polymorphicCall(i);
return 0;
}