可能重复:
是否可以编写 C++ 模板来检查函数是否存在?
我正在尝试编写一个 C++ 类模板。我想要的是当这个类模板与用户定义的类一起使用时,我想强制那些用户定义的类实现某些方法,例如,to_data
和from_data
。我不想要那些用于基本 C++ 原始数据类型的东西。我该怎么做呢?例如,std::vector
如果类的复制构造函数不可用,则给出编译错误。
可能重复:
是否可以编写 C++ 模板来检查函数是否存在?
我正在尝试编写一个 C++ 类模板。我想要的是当这个类模板与用户定义的类一起使用时,我想强制那些用户定义的类实现某些方法,例如,to_data
和from_data
。我不想要那些用于基本 C++ 原始数据类型的东西。我该怎么做呢?例如,std::vector
如果类的复制构造函数不可用,则给出编译错误。
Simply use the methods in your class template:
template <typename T>
struct Serializer
{
void serialize(T const & t) const { write(t.to_data()); }
void deserialize(T & t) const { t.from_data(read()); }
};
If the types you instantiate the template with have the appropriate member functions, everything will be fine. If they don't, the compiler will trigger an error:
struct Foo
{
int val;
int to_data() const { return val; }
void from_data(int i) { val = i; }
};
struct Bar {};
Serializer<Foo> sf;
sf.serialize(); // OK
Serializer<Bar> sb;
sb.serialize(); // compiler error: Bar has no member function named "to_data"
Note that the compiler error is only triggered when we try to use some functions of the class template. This is because member functions of class templates are only instantiated (compiled, if you will) when you use them. So it is perfectly fine to instantiate Serializer
with Bar
as long as you don't use the serialize
and deserialize
member function.
Regarding the second issue, namely how to provide a different behavior for primitive types, you have several solutions. The first one is to specialize your class template for the types you want to handle differently. For instance, the following code specializes Serializer
so that it handles int
differently:
template <>
struct Serializer<int>
{
void serialize(int i) const { write(i); }
void deserialize(int & i) const { i = read();
};
However, this implies writing a specialization for each particular type, even if some of them are in fact handled in the same way.
A less cumbersome solution would be to use type traits and std::enable_if
to select the correct implementation depending on some characteristics of the arguments types (in this case, whether they are primitive or not):
#include <type_traits>
template <typename T, typename Enable = void>
struct Serializer
{
// same as before
};
// Partial specialization for fundamental types
template <typename T>
struct Serializer<T, typename
std::enable_if<std::is_fundamental<T>::value>::type>
{
void serialize(T t) const { write(t); }
void deserialize(T & t) const { t = read(); }
};
Serializer<Foo> sf; // first implementation
Serializer<int> si; // second (specialized) implementation
You can make the methods that must be implemented by user pure virtual functions. If you don't want those for basic C++ primitive datatypes, you can specialize your template for these situations and provide default implementations for these cases.