3

Is it possible to declare a template function where a certain type is derived from let's say B?

My goal is to achieve something like this:

template<class T : std::ostream> void write(T os) {
    os << "...";
} 

template<class T : std::string> void write(T s) {
   // ...
}

Edit: I know it is not a solid example since it is not usual to derive from a string, but note that it's just a example.

So any solution like a workaround is welcome, however I would like to be able to explicit instantiate the template functions.

Tim
  • 5,521
  • 8
  • 36
  • 69
  • [is_base_of](http://www.cplusplus.com/reference/type_traits/is_base_of/) – aaronman Jun 19 '13 at 16:03
  • 1
    You don't need templates for that. If you take the parameter by reference to the base class, you can pass anything that derives from it. – jrok Jun 19 '13 at 16:03
  • @jrok I think the whole point is that he wants to use a template – aaronman Jun 19 '13 at 16:06
  • @jrok I'm aiming for speed. ;) – Tim Jun 19 '13 at 16:06
  • A template shouldn't be any faster than a regular inline function. Passing by reference will be faster if you would otherwise incur a copy. I see no reason to use a template unless you need access to non-inherited members of T. – Oktalist Jun 19 '13 at 16:17
  • @Oktalist You can't call a overloaded function which was inheritated from a base class by passing by reference. Besides `std::ostream` was like it says in the question just a example. – Tim Jun 19 '13 at 16:22
  • @Tim yes you can. Are you sure the function is really inherited? I didn't mention `std::ostream`. – Oktalist Jun 19 '13 at 16:28
  • @Oktalist Sorry confused you with jrok. Sure you can call a base class function on a base class reference, but it certainly won't call the derived class function which may be overloaded. If you're talking about pointers, it would be possible, but then it would be slower than templates. – Tim Jun 19 '13 at 16:31
  • @Tim OK you need access to non-inherited members of T, so you need a template, that's fine. But you have a different, bigger problem if your derived classes redefine non-virtual functions of their base classes. You'll break your base classes' invariants and encounter inconsistent behaviour. – Oktalist Jun 19 '13 at 17:12
  • @Oktalist Depends on the design, but you're about that though. However it is still not possible to call a overloaded virtual function from the derived class through a base class reference. So it doesn't make sense to use the reference unless you stick with the std::ostream design it might... – Tim Jun 19 '13 at 17:33
  • @Tim Yes you can call a derived class virtual function thru a reference to base, references and pointers behave the same in that regard. If you want to avoid the minor overhead of a vtable lookup, your template is fine, although the overhead of passing by lvalue is still likely to be bigger. – Oktalist Jun 19 '13 at 18:10
  • @Oktalist Damn you're right. Didn't know that. But if the template argument were a reference too it would sigfinicantly matter right. Thanks for your feedback! – Tim Jun 19 '13 at 18:31

2 Answers2

9

Yes, using C++11 <type_traits> it can be achieved.
If you only have C++03, you can use Boost's <type_traits> instead.

template <typename T>
typename std::enable_if<std::is_base_of<std::ostream, T>::value>::type
write(T& os) {
}
iammilind
  • 68,093
  • 33
  • 169
  • 336
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Thank you very much, exactly where I was looking for! – Tim Jun 19 '13 at 16:07
  • Good answer .. too quick. – iammilind Jun 19 '13 at 16:07
  • Are you sure your edit is correct? The syntax is not familiar to me. – Tim Jun 19 '13 at 16:17
  • 1
    Yes, the edit is correct. Good catch. @Tim, google for "dependent typename". – Sebastian Redl Jun 19 '13 at 16:19
  • @Tim the `typename std::enable_if<...>::type` is the function's return type, void if the `<...>` is true, otherwise it is a substitution failure. – Oktalist Jun 19 '13 at 16:25
  • @Oktalist Ah now I see, but it was about the first argument. I don´t really understand the occurrance of the keyword `typename` though.. – Tim Jun 19 '13 at 16:27
  • @SebastianRedl Thanks I got it now. Could you provide an example with partial specialization, so that derived classes from both ostream and string are accepted? – Tim Jun 19 '13 at 19:58
  • @SebastianRedl In this form if possible: `template ::value>::type> void print(T value) { cout << value << endl; }` – Tim Jun 19 '13 at 20:01
0

Any object that derives from std::ostream can be used as parameter for

void write(std::ostream os) {
    os << "...";
} 
Felype
  • 3,087
  • 2
  • 25
  • 36