"? What does a "class" do in a template statement? Example: template class Something...">

Why is there a "class" in "template <class x>"?

What does a "class" do in a template statement?

Example:

template <class T>
class Something
{
    public:
        Something(const T &something);
}

      

What else can you go there? Usually I only see "class".

+4


source share


3 answers


Keyword class

means the same as keyword typename

. They both indicate that T is a type.

The only difference between the keyword class

and typename

is what class

can be used to provide a template pattern template argument pattern, whereas typename

can not. Consider:

template<template <class T> class U> // must be "class"
std::string to_string(const U<char>& u)
{
  return std::string(u.begin(),u.end());
}

      



The only thing you can add instead of keywords class

or typename

is an integral type. For example:

template<std::size_t max>
class Foo{...};
...
Foo<10> f;

      

For a specific example, see the std::bitset<N>

standard library.

+8


source


To define a template parameter, you either need to tell the compiler that the parameter is a type or a value.

At the beginning...

If I recall correctly, the C ++ committee was reluctant to add a new keyword to the C ++ language, and so they decided to allow the following notation:

template<int I>
int getTwice()
{
   return I * 2 ;
}

template<class T>
std::string getType(const T & t)
{
   return typeid(t).name() ;
}

void doSomething()
{
   std::cout << "25 : " << getTwice<25>() << std::endl ;
   std::cout << "5  : " << getTwice<5>() << std::endl ;

   std::cout << "type(25)   : " << getType(25) << std::endl ;
   std::cout << "type(25.5) : " << getType(25.5) << std::endl ;
   std::cout << "type(abc)  : " << getType("abc") << std::endl ;
}

      

What are the outputs, in g ++:

25 : 50
5  : 10
type(25)   : i
type(25.5) : d
type(abc)  : A4_c

      

The first designation was a pattern over a value. So we have a value type in our template declaration:

// "I" is the value, and "int" is the type of the value
template <int I>

      

The second notation was pattern over an unknown type, and the fact that the type was not "known" was flagged with the "class" keyword. So in this context "class" means "type".

// "T" is a type... And "class" is the "this-is-a-type" keyword
template <class T> 

      

You will notice that with the second note, despite the class keyword, T could be ... int or some other built-in type. But then it's better to have that curiosity than to add a new keyword, don't you agree? ...

Oops ...

Everything was fine and good until someone wrote the following code:

template<class T> // T could be any STL container, for example a vector<char>
void printContainerData(const T & t)
{
   std::cout << "aVector:" ;

   for(T::const_iterator it = t.begin(), itEnd = t.end(); it != itEnd; ++it)
   {
      std::cout << " " << (*it) ;
   }

   std::cout << std::endl ;
}

      

Where T :: const_iterator is a type, of course ... But then it can be a static member of the class of type T and therefore a value. The compiler can be quite confusing.

At the end...

The solution was to tell the compiler that T :: const_iterator is indeed of type ... Which would result in a notation like this:

for(class T::const_iterator it = t.begin(), // etc.

      

But that was considered impossible / correct (class refers to class declarations, no?). So by dragging their feet, they decided that the keyword was really needed to tell the compiler that this symbol was a type, not a value.

"type" was left out, I think, because creating a keyword would break a lot of code. So typename was used instead. With typename we can write:

for(typename T::const_iterator it = t.begin(), // etc.

      

And for consistency, we have to use:

template <typename T>

      

When T is assumed to be a type and not a value. But for compatibility reasons the old notation is:



template <class T>

      

still resolved.

What about??

eben suggested the answer above, the answer I wanted to comment on because it's quite interesting:

template<template <class T> class U> // must be "class"
std::string to_string(const U<char>& u)
{
  return std::string(u.begin(),u.end());
}

      

I will only comment on its "meaning" (this code cannot be used with STL containers in my g ++ compiler, but I don’t think it was not): One point, it puts a constraint on U saying: U is a templated class type T. This is part:

template <class T> class U

      

What can also be written:

template <typename T> class U

      

Because U is really and only a class (not a built-in type) and T is a type, any type.

The next line says that U is specialized over char:

std::string to_string(const U<char>& u)

      

So this "generic code" will only work for U if U is declared as:

template<typename T>
class U
{
   // Etc.
} ;

      

And U is induced via char:

U<char> u ;
// etc.
to_string(u)

      

But one thing has been forgotten: Eben's designation can be written in two ways:

template<template <class T> class U>
std::string to_string(const U<char>& u)

template<template <typename T> class U>
std::string to_string(const U<char>& u)

      

The second "class" keyword is not the "type" keyword. It is a type that is a class template over T. So the notation is confusing.

Another way to write Eben code that removes the restrictions above would be something like:

template<typename U>
std::string to_string(const U & u)
{
   return std::string(u.begin(),u.end());
}

      

And let the compiler do its magic:

std::list<char> myList ;
// etc.
std::cout << to_string(myList) << std:endl ;

      

(The Eben code didn't work with STL containers that have a "char" pattern on my g ++ compiler for example ...)

+8


source


You can also use the following template arguments:

  • any integral type short, int, long, bool

    , etc.
  • pointers to objects or functions
  • references to objects or functions
  • pointers to member objects or member functions

A few examples:

template<typename T, int N=4, bool Flag>
class myClass { /*...*/ };

template<typename T, const int& Reference, myClass * Pointer&gt
class someClass { /*...*/ };

template<typename T, int (T::*MemberFunctionPtr)(int, int)>
class anotherClass { /*...*/ };
      

+4


source







All Articles