Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Priority when choosing overloaded template functions in C++

I have the following problem:

class Base
{
};

class Derived : public Base
{
};

class Different
{
};

class X
{
public:
  template <typename T>
  static const char *func(T *data)
  {
    // Do something generic...
    return "Generic";
  }

  static const char *func(Base *data)
  {
    // Do something specific...
    return "Specific";
  }
};

If I now do

Derived derived;
Different different;
std::cout << "Derived: " << X::func(&derived) << std::endl;
std::cout << "Different: " << X::func(&different) << std::endl;

I get

Derived: Generic
Different: Generic

But what I want is that for all classes derived from Base the specific method is called. So the result should be:

Derived: Specific
Different: Generic

Is there any way I can redesign the X:func(...)s to reach this goal?

EDIT:

Assume that it is not known by the caller of X::func(...) if the class submitted as the parameter is derived from Base or not. So Casting to Base is not an option. In fact the idea behind the whole thing is that X::func(...) should 'detect' if the parameter is derived from Base or not and call different code. And for performance reasons the 'detection' should be made at compile time.

like image 487
mmmmmmmm Avatar asked Aug 26 '09 06:08

mmmmmmmm


People also ask

How template functions can be overloaded?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.

Which function is useful when template of template is used?

Explanation: As a template feature allows you to write generic programs. therefore a template function works with any type of data whereas normal function works with the specific types mentioned while writing a program.

What is the advantage of using template function over function overloading?

@kushal Yes but with template, the compiler create a new function for every type used, while with function overloading you keep control of how many function exist in the final program. Template makes the program bigger.

What is the relationship between function templates and overloading?

Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.


2 Answers

I found a VERY easy solution!

class Base
{
};

class Derived : public Base
{
};

class Different
{
};

class X
{
private:
  template <typename T>
  static const char *intFunc(const void *, T *data)
  {
    // Do something generic...
    return "Generic";
  }

  template <typename T>
  static const char *intFunc(const Base *, T *data)
  {
    // Do something specific...
    return "Specific";
  }

public:
  template <typename T>
  static const char *func(T *data)
  {
    return intFunc(data, data);
  }
};

This works great and is very slim! The trick is to let the compiler select the correct method by the (otherwise useless) first parameter.

like image 90
mmmmmmmm Avatar answered Sep 27 '22 20:09

mmmmmmmm


You must use SFINAE for this. In the following code, the first function can be instantiated if and only if you pass something that can't be (implicitly) converted to Base *. The second function has this reversed.

You might want to read up on enable_if.

#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

class Base {};
class Derived : public Base {};
class Different {};

struct X
{
    template <typename T>
    static typename boost::disable_if<boost::is_convertible<T *, Base *>,
        const char *>::type func(T *data)
    {
        return "Generic";
    }

    template <typename T>
    static typename boost::enable_if<boost::is_convertible<T *, Base *>,
        const char *>::type func(T *data)
    {
        return "Specific";
    }
};

int main()
{
    Derived derived;
    Different different;
    std::cout << "Derived: " << X::func(&derived) << std::endl;
    std::cout << "Different: " << X::func(&different) << std::endl;
}
like image 27
avakar Avatar answered Sep 27 '22 20:09

avakar