函数模板专业化语法聚合模板化类型
Function Template Specialization Syntax aggregating templated types
关于函数模板专业化,我需要一些语法方面的帮助。以下是一个简化的场景:
基础header:
template <typename T>
void Foo(T* t) { TRACE("Default Foo impl"); } // <-- default implementation
template <typename T>
struct Base
{
explicit Base()
{
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
Foo(static_cast<T*>(this));
}
};
Derived_X header:
struct Derived_X : public Base<Derived_X>
{
explicit Derived_X() : Base<Derived_X> { } { }
};
// no specialization will be implemented --> using default
Derived_Y header:
struct Derived_Y : public Base<Derived_Y>
{
explicit Derived_Y() : Base<Derived_Y> { } { }
};
template <> // Foo specialization for Derived_Y
void Foo<Derived_Y>(Derived_Y* t)
{
Foo(static_cast<Base<Derived_Y>*>(t)); // <-- call default impl
TRACE("Derived_Y Foo impl");
}
Derived_Z header:
template <typename T>
struct Derived_Z : public Base<T>
{
explicit Derived_Z() : Base<T> { }
{
static_assert(std::is_base_of<Derived_Z, T>::value, "T must derive from Derived_Z");
}
};
/* What does this specialization look like?
template <typename T>
void Foo<Derived_Z<T>>(Derived_Z<T>* t)
{
Foo(static_cast<Base<T>*>(t)); // <-- call default impl
TRACE("Derived_Z<T> Foo impl");
}
// */
MostDerived Header:
struct MostDerived : public Derived_Z<MostDerived>
{
explicit MostDerived() : Derived_Z<MostDerived> { } { }
};
template <>
void Foo<MostDerived>(MostDerived* t)
{
Foo(static_cast<Derived_Z<MostDerived>*>(t)); // <-- call Derived_Z impl
TRACE("MostDerived Foo impl");
}
用法:
int main()
{
Derived_X dx { }; // <-- "Default Foo impl"
Derived_Y dy { }; // <-- "Default Foo impl" && "Derived_Y Foo impl"
MostDerived md { }; // <-- "Default Foo impl" && "MostDerived Foo impl"
}
我无法确定如何将 Foo
专用于 Derived_Z
。任何帮助将不胜感激!
I have not been able to determine how to specialize Foo for Derived_Z.
这是因为您不能部分特化模板函数。
但您可以部分特化 class
/struct
。
所以我建议使用助手struct
template <typename T>
struct bar
{
static void func (T *)
{ std::cout << "default bar" << std::endl; }
};
template <>
struct bar<Derived_Y>
{
static void func (Derived_Y *)
{ std::cout << "Derived_Y bar" << std::endl; }
};
template <typename T>
struct bar<Derived_Z<T>>
{
static void func (Derived_Z<T> *)
{ std::cout << "Derived_Z<T> bar" << std::endl; }
};
和Foo()
就变成了
template <typename T>
void Foo (T * t)
{ bar<T>::func(t); }
通常认为特化函数模板的形式不佳。您将无法部分专业化(正如您所注意到的),并且在重载解决方案中不会考虑它们。相反,只需创建重载,让重载解析处理其余部分。
// no template at all for Derived_Y
void Foo(Derived_Y* t)
{
Foo(static_cast<Base<Derived_Y>*>(t)); // <-- call default impl
TRACE("Derived_Y Foo impl");
}
// a regular template (no specialization) for Derived_Z<T>
template <typename T>
void Foo(Derived_Z<T>* t)
{
Foo(static_cast<Base<T>*>(t)); // <-- call default impl
TRACE("Derived_Z<T> Foo impl");
}
// again, no template for MostDerived
void Foo(MostDerived* t)
{
Foo(static_cast<Derived_Z<MostDerived>*>(t)); // <-- call Derived_Z impl
TRACE("MostDerived Foo impl");
}
现在,您可能要考虑将基本实现更改为仅接受 Base<T>*
而不是 T*
。假设您有 Derived_Y2
派生自 Derived_Y
,但您没有为 Foo(Derived_Y2*)
定义重载。使用指向 Derived_Y2
的指针调用 Foo()
将转到 Foo(T*)
,其中 T
被推断为 Derived_Y2
,因为这比 [= 更匹配23=]
struct Derived_Y2 : Derived_T { };
Derived_Y2 y2; // "Default Foo impl"
通过将基础实现更改为:
template<class T>
void Foo(Base<T>*) { TRACE("Default Foo impl"); }
Foo(Derived_Y*)
现在在给定指向 Derived_Y2
的指针时将是更好的匹配,因为正如他们所说,它 更专业 。
关于函数模板专业化,我需要一些语法方面的帮助。以下是一个简化的场景:
基础header:
template <typename T>
void Foo(T* t) { TRACE("Default Foo impl"); } // <-- default implementation
template <typename T>
struct Base
{
explicit Base()
{
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
Foo(static_cast<T*>(this));
}
};
Derived_X header:
struct Derived_X : public Base<Derived_X>
{
explicit Derived_X() : Base<Derived_X> { } { }
};
// no specialization will be implemented --> using default
Derived_Y header:
struct Derived_Y : public Base<Derived_Y>
{
explicit Derived_Y() : Base<Derived_Y> { } { }
};
template <> // Foo specialization for Derived_Y
void Foo<Derived_Y>(Derived_Y* t)
{
Foo(static_cast<Base<Derived_Y>*>(t)); // <-- call default impl
TRACE("Derived_Y Foo impl");
}
Derived_Z header:
template <typename T>
struct Derived_Z : public Base<T>
{
explicit Derived_Z() : Base<T> { }
{
static_assert(std::is_base_of<Derived_Z, T>::value, "T must derive from Derived_Z");
}
};
/* What does this specialization look like?
template <typename T>
void Foo<Derived_Z<T>>(Derived_Z<T>* t)
{
Foo(static_cast<Base<T>*>(t)); // <-- call default impl
TRACE("Derived_Z<T> Foo impl");
}
// */
MostDerived Header:
struct MostDerived : public Derived_Z<MostDerived>
{
explicit MostDerived() : Derived_Z<MostDerived> { } { }
};
template <>
void Foo<MostDerived>(MostDerived* t)
{
Foo(static_cast<Derived_Z<MostDerived>*>(t)); // <-- call Derived_Z impl
TRACE("MostDerived Foo impl");
}
用法:
int main()
{
Derived_X dx { }; // <-- "Default Foo impl"
Derived_Y dy { }; // <-- "Default Foo impl" && "Derived_Y Foo impl"
MostDerived md { }; // <-- "Default Foo impl" && "MostDerived Foo impl"
}
我无法确定如何将 Foo
专用于 Derived_Z
。任何帮助将不胜感激!
I have not been able to determine how to specialize Foo for Derived_Z.
这是因为您不能部分特化模板函数。
但您可以部分特化 class
/struct
。
所以我建议使用助手struct
template <typename T>
struct bar
{
static void func (T *)
{ std::cout << "default bar" << std::endl; }
};
template <>
struct bar<Derived_Y>
{
static void func (Derived_Y *)
{ std::cout << "Derived_Y bar" << std::endl; }
};
template <typename T>
struct bar<Derived_Z<T>>
{
static void func (Derived_Z<T> *)
{ std::cout << "Derived_Z<T> bar" << std::endl; }
};
和Foo()
就变成了
template <typename T>
void Foo (T * t)
{ bar<T>::func(t); }
通常认为特化函数模板的形式不佳。您将无法部分专业化(正如您所注意到的),并且在重载解决方案中不会考虑它们。相反,只需创建重载,让重载解析处理其余部分。
// no template at all for Derived_Y
void Foo(Derived_Y* t)
{
Foo(static_cast<Base<Derived_Y>*>(t)); // <-- call default impl
TRACE("Derived_Y Foo impl");
}
// a regular template (no specialization) for Derived_Z<T>
template <typename T>
void Foo(Derived_Z<T>* t)
{
Foo(static_cast<Base<T>*>(t)); // <-- call default impl
TRACE("Derived_Z<T> Foo impl");
}
// again, no template for MostDerived
void Foo(MostDerived* t)
{
Foo(static_cast<Derived_Z<MostDerived>*>(t)); // <-- call Derived_Z impl
TRACE("MostDerived Foo impl");
}
现在,您可能要考虑将基本实现更改为仅接受 Base<T>*
而不是 T*
。假设您有 Derived_Y2
派生自 Derived_Y
,但您没有为 Foo(Derived_Y2*)
定义重载。使用指向 Derived_Y2
的指针调用 Foo()
将转到 Foo(T*)
,其中 T
被推断为 Derived_Y2
,因为这比 [= 更匹配23=]
struct Derived_Y2 : Derived_T { };
Derived_Y2 y2; // "Default Foo impl"
通过将基础实现更改为:
template<class T>
void Foo(Base<T>*) { TRACE("Default Foo impl"); }
Foo(Derived_Y*)
现在在给定指向 Derived_Y2
的指针时将是更好的匹配,因为正如他们所说,它 更专业 。