C++ 嵌套模板专门化是如何在C++;
我有一个模板函数定义为:C++ 嵌套模板专门化是如何在C++;,c++,templates,C++,Templates,我有一个模板函数定义为: template<typename TObject> TObject Deserialize(long version, const Value &value) 模板对象反序列化(长版本、常量值和值) 我需要做的是编写一个特殊化,它将向量定义为: template<typename TNum, int cnt> class Vec 模板类Vec 并且仍然可以使用cnt和TNum 我试过,但没有成功 template<type
template<typename TObject> TObject Deserialize(long version, const Value &value)
模板对象反序列化(长版本、常量值和值)
我需要做的是编写一个特殊化,它将向量定义为:
template<typename TNum, int cnt> class Vec
模板类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 << "generic\n";
return {};
}
template<typename T, std::size_t N>
std::array<T,N> Deserialize_impl(long version, tag<std::array<T,N>>) {
std::cerr << "special\n";
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;
}
#包括
#包括
#包括
#包括
#包括
我通常认为这些方法比使用静态方法(这里的另一种主要方法)对结构进行部分专门化更可取,因为函数有很多优点,与专门化相比,它的行为更直观。YMMV.通常,处理函数模板并需要部分专门化它们的正确答案是简单地重载它们。在这种情况下,此技巧不会直接起作用,因为没有依赖于模板参数的参数,即模板参数是显式指定的,而不是推导的。但是,您可以转发到实现函数,并通过使用简单的标记结构使重载工作
#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 << "generic\n";
return {};
}
template<typename T, std::size_t N>
std::array<T,N> Deserialize_impl(long version, tag<std::array<T,N>>) {
std::cerr << "special\n";
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;
}
#包括
#包括
#包括
#包括
#包括
我通常认为这些方法比使用静态方法(这里的另一种主要方法)对结构进行部分专门化更可取,因为函数有很多优点,与专门化相比,它的行为更直观。YMMV.虽然函数标记分派是一种很好的方法,但这里有一个类专门化版本供比较。两者都有各自的用处,我不认为两者都是一个令人遗憾的决定,但也许其中一个更符合你的个人风格。
对于您编写的任何需要自定义反序列化处理程序的类,只需编写反序列化器类的专用化:
#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 impl\n";
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);
}
#包括
#包括
使用名称空间std;
使用Value=std::string;
//默认反序列化函数
样板
结构反序列化器{
静态ToObject反序列化(长版本、常量值和值){
虽然函数标记分派是一种很好的方法,但这里有一个类专门化版本供比较。两者都有各自的用途,我认为两者都不是一个天生令人遗憾的决定,但也许其中一个更符合您的个人风格。
对于您编写的任何需要自定义反序列化处理程序的类,只需编写反序列化器类的专用化:
#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 impl\n";
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);
}
#包括
#包括
使用名称空间std;
使用Value=std::string;
//默认反序列化函数
样板
结构反序列化器{
静态ToObject反序列化(长版本、常量值和值){
std::cout理想情况下,在这种情况下,Vec
应将其自身的模板参数反映为成员Vec::value\u type
和Vec::size()
,其应为constepr
如果类无法在自己的接口中提供自己的属性,下一个最好的方法是定义自己的扩展接口。在这种情况下,可以使用单独的元函数(如访问器函数)或traits类(如帮助器视图类)。我更喜欢后者:
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;
…
}
模板
结构载体性状;
模板
结构向量特征>{
typedef TNum value_type;
constexpr static int size=cnt;
};
模板TVec反序列化(长版本、值和值){
typedef载体_性状性状;
typedef typename traits::value_type TNum;
constexpr static int cnt=traits::size;
…
}
此解决方案适用于任何现有函数,甚至使签名更干净。此外,该函数更灵活,因为您可以通过添加traits
专门化而不是整个新的重载来调整它。理想情况下,Vec
应将其自身的模板参数反映为成员Vec::value_键入
和Vec::size()
,它们应该是constepr
如果类无法在自己的接口中提供自己的属性,下一个最好的方法是定义自己的扩展接口。在这种情况下,可以使用单独的元函数(如访问器函数)或traits类(如帮助器视图类)。我更喜欢后者:
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;
…
}
模板
结构载体性状;
模板
结构向量特征>{
typedef TNum value_type;
constexpr static int size=cnt;
};
模板TVec反序列化(长版本、值和值){
typedef载体_性状性状;
typedef typename traits::value_type TNum;
constexpr static int cnt=traits::size;
…
}
此解决方案适用于任何现有函数,甚至使签名更清晰。此外,该函数更灵活,因为您可以通过添加traits
专门化而不是整个新的重载来调整它。您不能部分专门化函数。因此,您必须将实际实现隐藏到d的静态方法中ummy template struct,并专门化整个结构。只有一个向量或任何容器?@HolyBlackCat我希望不要这么快给出这个建议。9/10倍的正确答案是重载,而不是转发到结构。函数没有部分专门化,因为它们只是