开发者

What is the use of member template functions in c++?

开发者 https://www.devze.com 2022-12-21 11:51 出处:网络
Given a class with a member template function like this one: template <typename t> class complex {

Given a class with a member template function like this one:

template <typename t>
class complex
{
public:
    complex(t r, t im);
    template<typename u>
    complex(cons开发者_Python百科t complex<u>&);
private:
    //what would be the type of real and imaginary data members here.
}

I am confused about member template functions, please provide an example by which the need of member template functions becomes clear to me.

Also, tell me the use of member template functions in c++, what are the situations where we use member template functions?


It gives you the ability to do conversions:

complex<int> ci;

complex<float> cf(ci);

So, if you have two types T1 and T2 and you can assign a T1 to a T2, this will make it possible to assign a complex<T1> to a complex<T2>.

As for the question in your code (what would be the type of real and imaginary data members here):

template <typename t>
class complex
{
...
private:
    t real_part;
    t imaginary_part;
};


The most common valuable use for member template functions I come across in my day-to-day is to reduce code complexity by providing one templated function instead of many functions that do essentially the same thing.

For example, suppose you are working on a server that receives half a dozen related messages and saves the incoming data to half a dozen tables in a database. A straightforward implementation would be to implement 6 message handling functions (psudocode):

class MessageProcessor
{
  void OnMessage(const char* msg);
  void ProcessMessage100(Data100* data);
  void ProcessMessage101(Data101* data);
  void ProcessMessage102(Data102* data);
  void ProcessMessage103(Data103* data);
  void ProcessMessage104(Data104* data);
  void ProcessMessage105(Data105* data);
};

MessageProcessor::OnMessage(const char* msg)
{
  unsigned int * msgType = ((unsigned int*)msg);
  switch( *msgType )
  { 
    case 100 :
      ProcessMessage100((Data100*),sg);
      break;
    case 101 :
      ProcessMessage101((Data101*),sg);
      break;
    ::
  }
}

MessageProcessor::ProcessMessage100(Data100* data)
{
  Record100* record = GetRecord100(key);
  record->SetValue(xyz);
}

MessageProcessor::ProcessMessage101(Data101* data)
{
  Record101* record = GetRecord101(key);
  record->SetValue(xyz);
}

: :

There is an opportunity here to generalize the ProcessMessage() functions, since they do essentially the same thing:

class MessageProcessor
{
  OnMessage(const char* msg);

  template<class Record, class Data> void Process(Data* data);
};

template<class Record, class Data> 
void MessageProcessor::Process<Record,Data>(Data* data)
{
  Record* record = GetRecord(key);
  record->SetValue(xyz);
}

The GetRecord function can also be generalized, yielding a codebase with 2 functions where there used to be 12. This improves the code by virtue of it being simpler with fewer moving parts, simpler to understand and maintain.


The general purpose and functionality of member function templates is in no way different from that of ordinary (non-member) function templates. The only [irrelevant] difference is that member functions have access to the implicit this parameter.

You understand the general purpose of ordinary function templates, do you? Well, in that case you should understand the general purpose of member function templates, because it is exactly the same.


Using the example you provided, the member template function allows you to construct an instance of complex<T> from complex<U>.

As a concrete example of when this might be useful, suppose you had a complex<double> but wanted a complex<float>. Without the constructor the types are unrelated so the regular copy constructor wouldn't work.


Often you would like some member function of your class to operate on a range. By having templated member functions you make it possible to operate on ranges independent of the container that supplies the range without providing an free function.

The same goes for Functors. Often you'd write a functor that operates on some sipecial pair of iterators but soon realize that it is possible to have the Functor operate on any kind of range. So instead of supplying the template parameters through the encapsulating struct you can supply them through the member function operator() and make type deduction possible.


The first examples that come to mind:

  • In some container constructors (or assign methods) to take input iterators of unknown type.

  • std::complex to allow operating on different types than the one the std::complex was instantiated from.

  • In shared_ptr (whether std::tr1:: or boost::) so that you can keep different types of pointers into a shared object instance in the heap (for which the pointer types can be obtained).

  • In thread (whether std:: in c++0x or boost::) to receive a functor of unknown type that will be called by the thread instance.

In all cases the usage is the same: you have a function that operates on types that are unknown. As AndreyT perfectly states the same that with regular functions.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号