嵌套模板专用化是如何C++完成的
How is nested template specialization done C++
我有一个模板化函数定义为:
template<typename TObject> TObject Deserialize(long version, const Value &value)
我需要做的是编写一个专业化,它将采用定义为:
template<typename TNum, int cnt> class Vec
并且仍然可以使用CNT和TNum。
我尝试过不成功
template<typename TNum, int cnt> Vec<TNum, cnt> Deserialize<Vec<TNum, cnt>>(long version, Value &value)
导致错误:非法使用显式模板参数
正确的方法是什么?
通常,处理函数模板并需要部分专用化它们的正确答案是简单地重载它们。在这种情况下,这个技巧不能直接工作,因为没有依赖于模板参数的参数,即模板参数是显式指定的而不是推导的。但是,您可以转发到实现函数,并使用简单的标记结构进行重载工作。
#include <functional>
#include <iostream>
#include <type_traits>
#include <vector>
#include <array>
template <class T>
struct tag{};
template<typename TObject>
TObject Deserialize_impl(long version, tag<TObject>) {
std::cerr << "genericn";
return {};
}
template<typename T, std::size_t N>
std::array<T,N> Deserialize_impl(long version, tag<std::array<T,N>>) {
std::cerr << "specialn";
return {};
}
template<typename TObject>
TObject Deserialize(long version) {
return Deserialize_impl(version, tag<TObject>{});
}
int main() {
Deserialize<int>(0);
Deserialize<std::array<int,3>>(0);
return 0;
}
现场示例:http://coliru.stacked-crooked.com/a/9c4fa84d2686997a
我通常发现这些方法比使用静态方法(此处的另一种主要方法)对结构进行部分特化非常可取,因为您可以通过函数利用很多东西,并且与专用化相比,它的行为更直观。扬子晚报.
虽然函数式标签调度是一种不错的方法,但这里有一个类专用化版本进行比较。 两者都有其用途,我不认为任何一个本质上是一个令人遗憾的决定,但也许一个更符合你的个人风格。 对于您编写的任何需要自定义反序列化处理程序的类,只需编写 Deserializer 类的专用化:
#include <iostream>
#include <string>
using namespace std;
using Value = std::string;
// default deserialize function
template <typename TObject>
struct Deserializer {
static TObject deserialize(long version, const Value &value) {
std::cout << "default impln";
return TObject();
}
};
// free standing function (if you want it) to forward into the classes
template <typename TObject>
TObject deserialize(long version, const Value &value) {
return Deserializer<TObject>::deserialize(version, value);
}
// Stub example for your Vec class
template<typename TNum, int cnt> class Vec { };
// Stub example for your Vec deserializer specialization
template <typename TNum, int cnt> struct Deserializer<Vec<TNum, cnt>> {
static auto deserialize(long version, const Value &value) {
std::cout << "specialization impl: cnt=" << cnt << "n";
return Vec<TNum, cnt>();
}
};
int main() {
Value value{"abcdefg"};
long version = 1;
deserialize<int>(version, value);
deserialize<Vec<int, 10>>(version, value);
}
理想情况下,Vec
应将自己的模板参数反映为成员Vec::value_type
,并Vec::size()
应constexpr
。
如果类无法在自己的接口中提供自己的属性,下一个最好的办法是定义自己的扩展接口。在这种情况下,可以具有单独的元函数(如访问器函数)或特征类(如帮助程序视图类)。我更喜欢后者:
template< typename >
struct vector_traits;
template< typename TNum, int cnt >
struct vector_traits< Vec< TNum, cnt > > {
typedef TNum value_type;
constexpr static int size = cnt;
};
template<typename TVec> TVec Deserialize(long version, Value &value) {
typedef vector_traits< TVec > traits;
typedef typename traits::value_type TNum;
constexpr static int cnt = traits::size;
…
}
该解决方案适合任何现有功能,甚至使签名更清晰。此外,该功能更加灵活,因为您可以通过添加traits
专用化而不是全新的重载来调整它。
相关文章:
- .cpp和.h文件中的模板专用化声明
- 调用专用模板时出错"no matching function for call to [...]"
- 模板专用化(按容器):value_type
- 静态数据成员模板专用化的实例化点在哪里
- 特征 3 类的模板专用化
- Visual Studio 2017 不允许我创建 C++ 专用模板
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 具有常量引用参数的函数模板专用化
- 使用其他模板的模板专用化
- 使用专用显卡进行 OpenGL 渲染时帧速率较低
- 嵌套模板显式专用化
- 如何检查模板专用化是否是基本模板的子类?
- C++:部分模板专用化用例
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 使用对象的基类部分模板专用化对对象进行哈希处理::哈希
- 在 C++20 中是否不再允许在 std 中对程序定义类型的函数模板进行专用化?
- 为什么依赖模板类型在部分专用化中不可推导?
- 如何为静态常量模板化专用整数值分配存储
- 模板类的部分模板专用化,如 std::function
- 合并一组模板专用化