如何正确设计和实现函数模板特化?
How to design and implement function template specialization properly?
我想实现 std::ifstream
的一些读取功能。
它需要区分 Pod 类型和其他类型。 (目前 std::string
)
template <typename T, typename = std::enable_if<std::is_pod<T>::value>::type>
T read(std::ifstream& fin);
template <>
std::string read<std::string, void>(std::ifstream& fin);
int main()
{
std::ifstream fin("test", std::ios::binary);
int x = read<int>(fin);
std::string str = read<std::string, void>(fin);
}
我想在为 std::string
调用读取时从模板参数中删除“void
”。
我怎样才能得到它?
提前致谢。
更新(2017/09/14)
我得到了 EC++ 的提示,并尝试实现以下代码。
template <bool B>
struct is_fundamental {
enum { value = B };
};
template <typename T>
static T doRead(std::ifstream& fin, is_fundamental<true>);
template <typename T>
static T doRead(std::ifstream& fin, is_fundamental<false>);
template <>
static std::string doRead<std::string>(std::ifstream& fin, is_fundamental<false>);
template <typename T>
static T read(std::ifstream& fin) {
return doRead<T>(fin, is_fundamental<std::is_fundamental<T>::value>());
}
int main()
{
std::string filename("./test.dat");
std::ifstream fin(filename, std::ios::binary);
read<int>(fin);
read<std::string>(fin);
read<std::vector<int>>(fin);
return 0;
}
每次读取<>调用都获得正确的功能!
问题是无法部分特化一个函数。
结构体的使用呢?
如果您编写 read
广告,
template <typename T>
struct read
{
template <typename U = T>
typename std::enable_if<std::is_same<U, T>::value
&& std::is_pod<T>::value, T>::type
operator() (std::ifstream & fin)
{ /* do something; return a T */ }
};
template <>
struct read<std::string>
{
std::string operator() (std::ifstream & fin)
{ /* do something; return a string */ }
};
你有一个通用版本的 read
结构,其中 operator()
仅在模板类型为 POD
的情况下启用,而 std::string
的专用版本(并且您可以添加 read
的其他特化;也可以添加部分特化)。
缺点是你必须这样改变read()
的调用
int x = read<int>{}(fin);
std::string str = read<std::string>{}(fin);
即定义一个对象(read<T>{}
).
如果您更喜欢在读取中使用静态成员——例如,func()
——您可以避免创建对象的需要,但您必须以这种方式调用它
int x = read<int>::func(fin);
std::string str = read<std::string>::func(fin);
以下是完整的工作示例
#include <vector>
#include <fstream>
#include <iostream>
#include <type_traits>
template <typename T>
struct read
{
template <typename U = T>
typename std::enable_if<std::is_same<U, T>::value
&& std::is_pod<T>::value, T>::type
operator() (std::ifstream & fin)
{ T ret ; std::cout << "POD!" << std::endl ; fin >> ret ; return ret; }
};
template <>
struct read<std::string>
{
std::string operator() (std::ifstream & fin)
{ std::string ret ; std::cout << "string!" << std::endl; fin >> ret ;
return ret; }
};
int main()
{
std::ifstream fin("test", std::ios::binary);
int x = read<int>{}(fin); // write POD!
std::string str = read<std::string>{}(fin); // write string!
//auto read<std::vector<int>>{}(fin); // compilation error
}
作为替代方案,您可以使用重载和标记调度:
template <typename> struct Tag {};
template <typename T, std::enable_if_t<std::is_pod<T>::value>* = nullptr>
T read(Tag<T>, std::ifstream& fin);
std::string read(Tag<std::string>, std::ifstream& fin);
并使用它:
int main()
{
std::ifstream fin("test", std::ios::binary);
int x = read(Tag<int>{}, fin); // write POD!
auto str = read(Tag<std::string>{}, fin); // write string!
//auto v = read(Tag<std::vector<int>>{}, fin); // compilation error
}
我想实现 std::ifstream
的一些读取功能。
它需要区分 Pod 类型和其他类型。 (目前 std::string
)
template <typename T, typename = std::enable_if<std::is_pod<T>::value>::type>
T read(std::ifstream& fin);
template <>
std::string read<std::string, void>(std::ifstream& fin);
int main()
{
std::ifstream fin("test", std::ios::binary);
int x = read<int>(fin);
std::string str = read<std::string, void>(fin);
}
我想在为 std::string
调用读取时从模板参数中删除“void
”。
我怎样才能得到它?
提前致谢。
更新(2017/09/14)
我得到了 EC++ 的提示,并尝试实现以下代码。
template <bool B>
struct is_fundamental {
enum { value = B };
};
template <typename T>
static T doRead(std::ifstream& fin, is_fundamental<true>);
template <typename T>
static T doRead(std::ifstream& fin, is_fundamental<false>);
template <>
static std::string doRead<std::string>(std::ifstream& fin, is_fundamental<false>);
template <typename T>
static T read(std::ifstream& fin) {
return doRead<T>(fin, is_fundamental<std::is_fundamental<T>::value>());
}
int main()
{
std::string filename("./test.dat");
std::ifstream fin(filename, std::ios::binary);
read<int>(fin);
read<std::string>(fin);
read<std::vector<int>>(fin);
return 0;
}
每次读取<>调用都获得正确的功能!
问题是无法部分特化一个函数。
结构体的使用呢?
如果您编写 read
广告,
template <typename T>
struct read
{
template <typename U = T>
typename std::enable_if<std::is_same<U, T>::value
&& std::is_pod<T>::value, T>::type
operator() (std::ifstream & fin)
{ /* do something; return a T */ }
};
template <>
struct read<std::string>
{
std::string operator() (std::ifstream & fin)
{ /* do something; return a string */ }
};
你有一个通用版本的 read
结构,其中 operator()
仅在模板类型为 POD
的情况下启用,而 std::string
的专用版本(并且您可以添加 read
的其他特化;也可以添加部分特化)。
缺点是你必须这样改变read()
的调用
int x = read<int>{}(fin);
std::string str = read<std::string>{}(fin);
即定义一个对象(read<T>{}
).
如果您更喜欢在读取中使用静态成员——例如,func()
——您可以避免创建对象的需要,但您必须以这种方式调用它
int x = read<int>::func(fin);
std::string str = read<std::string>::func(fin);
以下是完整的工作示例
#include <vector>
#include <fstream>
#include <iostream>
#include <type_traits>
template <typename T>
struct read
{
template <typename U = T>
typename std::enable_if<std::is_same<U, T>::value
&& std::is_pod<T>::value, T>::type
operator() (std::ifstream & fin)
{ T ret ; std::cout << "POD!" << std::endl ; fin >> ret ; return ret; }
};
template <>
struct read<std::string>
{
std::string operator() (std::ifstream & fin)
{ std::string ret ; std::cout << "string!" << std::endl; fin >> ret ;
return ret; }
};
int main()
{
std::ifstream fin("test", std::ios::binary);
int x = read<int>{}(fin); // write POD!
std::string str = read<std::string>{}(fin); // write string!
//auto read<std::vector<int>>{}(fin); // compilation error
}
作为替代方案,您可以使用重载和标记调度:
template <typename> struct Tag {};
template <typename T, std::enable_if_t<std::is_pod<T>::value>* = nullptr>
T read(Tag<T>, std::ifstream& fin);
std::string read(Tag<std::string>, std::ifstream& fin);
并使用它:
int main()
{
std::ifstream fin("test", std::ios::binary);
int x = read(Tag<int>{}, fin); // write POD!
auto str = read(Tag<std::string>{}, fin); // write string!
//auto v = read(Tag<std::vector<int>>{}, fin); // compilation error
}