具有转发引用的静态多态性
Static polymorphism with forwarding references
我正在尝试使用静态多态性,如下面的简单示例所示。
#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;
}
问题是 polymorphicCall
中的 T
被推断为 Derived
,这样任何东西都可以传递给该函数,甚至 int
。有没有办法只接受 Base<Derived>
类型?
我尝试在模板参数上使用转发引用和 enable_if
,但我无法推断出 Base
s 模板参数。
有没有办法同时使用转发引用和静态多态性?
编辑:更新了代码示例以包含实际的转发引用以及如何尝试使用它。
显示的错误是:"error: invalid use of incomplete type 'struct Traits'"
我不确定在示例中的什么地方您需要知道 Derived
类型,但是您可以为每个 Base
实例化提供 Derived
类型特征:
template <typename>
struct derived_of;
template <typename Derived>
struct derived_of<Base<Derived>>
{
using type = Derived;
};
并将其与衰减的类型一起使用。
如果目标只是将 polymorphicCall
的使用限制在从 Base
派生的类型上,您可以使用 static_assert
和类型特征来实现。
#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;
}
我正在尝试使用静态多态性,如下面的简单示例所示。
#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;
}
问题是 polymorphicCall
中的 T
被推断为 Derived
,这样任何东西都可以传递给该函数,甚至 int
。有没有办法只接受 Base<Derived>
类型?
我尝试在模板参数上使用转发引用和 enable_if
,但我无法推断出 Base
s 模板参数。
有没有办法同时使用转发引用和静态多态性?
编辑:更新了代码示例以包含实际的转发引用以及如何尝试使用它。
显示的错误是:"error: invalid use of incomplete type 'struct Traits'"
我不确定在示例中的什么地方您需要知道 Derived
类型,但是您可以为每个 Base
实例化提供 Derived
类型特征:
template <typename>
struct derived_of;
template <typename Derived>
struct derived_of<Base<Derived>>
{
using type = Derived;
};
并将其与衰减的类型一起使用。
如果目标只是将 polymorphicCall
的使用限制在从 Base
派生的类型上,您可以使用 static_assert
和类型特征来实现。
#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;
}