我有一个模板函数,根据传递给它的typename
给我一个唯一的ID,如下所示:
template<typename T>
inline std::size_t get_component_type_id() noexcept
{
static_assert(std::is_base_of<Component, T>::value, "T must be of type Component.");
static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
return uniqueComponentId;
}
当我用get_component_type_id
拨打BaseClass
10次时,我会获得相同的ID。这非常有效。
但是,如果我将子类传递给该函数,我也希望得到相同的id。当我用ChildClass
调用它时,我会得到一个不同的ID。那是为什么?
答案 0 :(得分:4)
当实际get_component_type_id()
是Component
的孩子时,您可以尝试添加以T
为Component
作为模板参数的函数。
template<class T>
auto fn() noexcept
{
using type = std::conditional_t<std::is_base_of<Component, T>::value, Component, T>;
return get_component_type_id<type>();
}
答案 1 :(得分:3)
这是因为模板的实例化一旦被实例化,就与同一模板的第二实例化无关。这两个是单独的实体,并获得自己的静态变量。
PS:以下是一个视频:CppCon 2015: Arthur O'Dwyer “Lambdas from First Principles: A Whirlwind Tour of C++"”。该示例从6:00开始
答案 2 :(得分:2)
get_component_type_id<BaseClass>
和get_component_type_id<ChildClass>
是两个不同的功能。因此,您得到两个static size_t uniqueComponentId
,每个都有自己的值。
更新,以回应OP的评论
是的,有可能。你可以使用:
template <typename T>
inline std::size_t get_component_type_id(T*, std::false_type) noexcept
{
static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
return uniqueComponentId;
}
inline std::size_t get_component_type_id(BaseClass*, std::true_type) noexcept
{
static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
return uniqueComponentId;
}
template<typename T>
inline std::size_t get_component_type_id() noexcept
{
static_assert(std::is_base_of<Component, T>::value, "T must be of type Component.");
return get_component_type_id((T*)nullptr, typename std::is_convertible<T, BaseClass>::type{});
}
然而,它很脆弱。如果您希望从Component
派生的另一个类具有相同的行为,则需要进行实质性更改。
最好使用virtual
成员函数。
struct Component
{
virtual size_t get_type_id() const = 0;
};
struct BaseClass : Component
{
size_t get_type_id() const
{
static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
return uniqueComponentId;
}
};
struct ChildClass : BaseClass {};
现在,您可以根据需要在继承层次结构中的任何级别实现size_t get_type_id() const
。