1

Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?

I am trying to write a C++ class template. What I want is when this class template is used with user defined classes, I want to force those user defined classes to implemented certain methods say e.g., to_data and from_data. I do not want those for basic C++ primitive datatypes. How do I do this? For example, std::vector give compilation error if the copy constructor of the class is not available.

Community
  • 1
  • 1
Avinash
  • 12,851
  • 32
  • 116
  • 186
  • What is you declare some virtual methods (signature only) without definition ? (you can also declare pure virtual methods : "virtual void my_method(args) = 0;) – Neozaru Oct 03 '12 at 06:35
  • @iammilind: I don't think that is a duplicate.In fact both these Qs are pretty much unrelated AFAICS. – Alok Save Oct 03 '12 at 06:38
  • 2
    @Als It looks similar, but this question does add the extra twist of not requiring the methods for primitive types. – CrazyCasta Oct 03 '12 at 06:43

2 Answers2

1

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.

Sidharth Mudgal
  • 4,234
  • 19
  • 25
  • So one must provide a specialization for all the primitive types? Sounds like a lot of work. – juanchopanza Oct 03 '12 at 07:58
  • Doing so would mean that the class template can only be used with types that derive from a common base class (the one defining the pure virtual member functions). That defeats (more or less) the purpose of using templates in the first place. – Luc Touraille Oct 03 '12 at 08:56
1

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
Luc Touraille
  • 79,925
  • 15
  • 92
  • 137