A question about Template parameter

S

Saeed Amrollahi

Dear All
Hi

C++ allow to declare templates with various kind of template
parameters.
I wonder what are the applications of these two template parameters:
1. template<class> // no identifier for template parameter
class C1 {
};

How it differs from this one:
template<class T>
class C2 {
};

C1<int> c1;
C2<int> c2;

2. template template parameter:
template<template<class T> class A>
struct B {
A<int> a;
};

How it differs from this one:
template<class T> class A { /* ... */ };
struct B {
A<int> a;
};

In advance, than you for your help.
-- Saeed Amrollahi
 
F

Francesco S. Carta

Saeed Amrollahi said:
Dear All
Hi

C++ allow to declare templates with various kind of template
parameters.
I wonder what are the applications of these two template parameters:
1. template<class> // no identifier for template parameter
    class C1 {
    };

How it differs from this one:
    template<class T>
    class C2 {
    };

   C1<int> c1;
   C2<int> c2;

There is no difference, C1 omits to give a name to something that
wouldn't be used in any case.

I suppose that those template declarations should result in the
declaration of the following two classes:

class C1 {
};

class C2 {
};

whatever the amount of different instantiations, but different
instantiations still are considered as different types, hence you will
not be able to assign a C1<double> to a C1<int> and thus I suppose the
compiler will create something like

class C1_int {
};

class C1_double {
};

or whatever other mechanism to disambiguate at runtime.

I can see uses of such a simple template (e.g. exception objects to be
thrown and caught on a per-template-parameter-type basis)
2. template template parameter:
  template<template<class T> class A>
  struct B {
    A<int> a;
  };

How it differs from this one:
template<class T> class A { /* ... */ };
struct B {
  A<int> a;

};

The former is a single declaration, where the A class doesn't exist
outside of B, the latter is a double declaration (two different
classes are declared and can be used separately).

At least that's what I understand about all of this, hope that helps.
 
S

Saeed Amrollahi

There is no difference, C1 omits to give a name to something that
wouldn't be used in any case.

I suppose that those template declarations should result in the
declaration of the following two classes:

class C1 {

};

class C2 {

};

whatever the amount of different instantiations, but different
instantiations still are considered as different types, hence you will
not be able to assign a C1<double> to a C1<int> and thus I suppose the
compiler will create something like

class C1_int {

};

class C1_double {

};

or whatever other mechanism to disambiguate at runtime.

I can see uses of such a simple template (e.g. exception objects to be
thrown and caught on a per-template-parameter-type basis)




The former is a single declaration, where the A class doesn't exist
outside of B, the latter is a double declaration (two different
classes are declared and can be used separately).

At least that's what I understand about all of this, hope that helps.

Hi Francesco
Thanks for your clarification.
About question 1, I'm not convinced yet.
Why there is such facility in the language:
template<class>
class A {
/* there is no template parameter identifier */
int a;
};

A<int> a;
what is the advantage of such parameterization compare to
the plain class:
class A {
int a;
};

Regards,
-- Saeed Amrollahi
 
J

Juha Nieminen

Francesco S. Carta said:
I can see uses of such a simple template

There are situations where you want to declare (not define, but declare)
a template class. When you are doing such a declaration, you don't need the
template parameter for anything, and thus you can omit it.

One practical situation where you may need to do that is when declaring
a template class to be a friend of another class (something which
surprisingly few C++ programmers know how to do). In other words, something
like:

class A
{
template<typename> friend class B;
...
};

Here we are declaring that class B, which is a template class, is a
friend class of A. You could specify a name for the template parameter,
but since it's not used in the declaration, it can be omitted.

Complete example:

#include <iostream>

class A
{
template<typename> friend class B;
int i;

public:
A(int value): i(value) {}
};

template<typename T>
class B
{
public:
void foo(const A& obj) { std::cout << obj.i << std::endl; }
};

int main()
{
A a(5);
B<int> b;
b.foo(a);
}
 
F

Francesco S. Carta

Saeed Amrollahi said:
Hi Francesco
Thanks for your clarification.
About question 1, I'm not convinced yet.
Why there is such facility in the language:
  template<class>
  class A {
    /* there is no template parameter identifier */
    int a;
  };

  A<int> a;
what is the advantage of such parameterization compare to
the plain class:
  class A {
    int a;
  };

Regards,
  -- Saeed Amrollahi

I was about to post a weird example about how to use such a feature
with exceptions, but Juha dropped in with something different which I
happened not to know, and I think it's a far better example than mine
- hence I'll keep my example in my clipboard ;-)
 
F

Francesco S. Carta

Juha Nieminen said:
  There are situations where you want to declare (not define, but declare)
a template class. When you are doing such a declaration, you don't need the
template parameter for anything, and thus you can omit it.

  One practical situation where you may need to do that is when declaring
a template class to be a friend of another class (something which
surprisingly few C++ programmers know how to do). In other words, something
like:

    class A
    {
        template<typename> friend class B;
        ...
    };

  Here we are declaring that class B, which is a template class, is a
friend class of A. You could specify a name for the template parameter,
but since it's not used in the declaration, it can be omitted.

  Complete example:

#include <iostream>

class A
{
    template<typename> friend class B;
    int i;

 public:
    A(int value): i(value) {}

};

template<typename T>
class B
{
 public:
    void foo(const A& obj) { std::cout << obj.i << std::endl; }

};

int main()
{
    A a(5);
    B<int> b;
    b.foo(a);

}

Well, I'm among those that didn't know that, indeed, thanks a lot for
pointing that out, it will come useful for sure - interesting thread.
 
P

Paul Bibbings

Saeed Amrollahi said:
C++ allow to declare templates with various kind of template
parameters.
I wonder what are the applications of these two template parameters:
1. template<class> // no identifier for template parameter
class C1 {
};

How it differs from this one:
template<class T>
class C2 {
};

C1<int> c1;
C2<int> c2;

As given there is essentially no difference since, with the
definition of both C1 and C2, you make no use of the template
parameter type. Note: it would be /possible/ to do so in the case of
C2, but not for C1 since the parameter is not named.

This is really no different than what you find in the case of ordinary
function calls that use unnamed function call parameters:

#include <iostream>

void f(int) // unnamed function call parameter - int
{
std::cout << "Calling void f(int)...\n";
}

void f(char c) // named function call parameter - char
{
std::cout << "Calling void f(char c) "
<< "with c = '" << c << "'...\n";
}

int main()
{
f(1);
f('1');
}

/**
* Output:
* Calling void f(int)...
* Calling void f(char c) with c = '1'...
*/

Again, inside the body of void f(char c) the function call argument
/could/ be used, since it is named, but not inside the body of void
f(int).

Note: in the case of C1, even though the template parameter is not
named (and so cannot be used in the definition of the class) the
compiler still knows what the template argument is that matches it
and so it can be `reconstructed' later, elsewhere. Consider:

#include <string>
#include <iostream>

template<class> // unnamed template parameter, but...
class C1 { };

template<class T>
std::string print_type();

template<>
std::string print_type<int>()
{
return "T = int";
}

template<class T>
void f(C1<T>) // ... T can still be deduced here
{
std::cout << "Calling void f(C1<T>) with ["
<< print_type<T>()
<< "]...\n";
}

int main()
{
C1<int> c1;
f(c1);
}

/**
* Output:
2. template template parameter:
template<template<class T> class A>
struct B {
A<int> a;
};

How it differs from this one:
template<class T> class A { /* ... */ };
struct B {
A<int> a;
};

In the case of your second type B, the type of the member a is hard
coded: it is your class A. For your first type B, however, A is a
template template parameter and so it can be matched by other template
types, for instance:

template<class T> class NotA { /* ... */ };
B<NotA> b;

Note, also, that there is a difference in the syntax of declarations.
For the first you have to specify a template argument, which is not
the case for the second.

Regards

Paul Bibbings
 
P

Paul Bibbings

Saeed Amrollahi said:
About question 1, I'm not convinced yet.
Why there is such facility in the language:
template<class>
class A {
/* there is no template parameter identifier */
int a;
};

A<int> a;
what is the advantage of such parameterization compare to
the plain class:
class A {
int a;
};

In your example as given there is no advantage. For your first
definition you have parameterized A for no reason at all. However, this
does not have any bearing on whether there /are/ reasons for which a
type may be parameterized where the name of the parameter is not used
*directly* in the definition of the class itself.

The following is perhaps not the best example, but hopefully illustrates
possible uses. Here, the parameterization of select_on_type<> is used
to control which types of ShortOrIntOnly may be instantiated:

template<class> struct select_on_type { }; // #1

template<>
struct select_on_type<short> {
typedef short type;
};

template<>
struct select_on_type<int> {
typedef int type;
};

template<
typename T,
template said:
struct ShortOrIntOnly {
typename Selector<T>::type t;
};

int main()
{
ShortOrIntOnly<short> soi1; // OK
ShortOrIntOnly<int> soi2; // OK
ShortOrIntOnly<char> soi3; // Error
}

In the above code you will see a couple of places (#1 and #2) where it
is appropriate to use the syntax template<class> without requiring an
identifier for the template parameter. The syntax, as used here, does
not detract from the purpose of the type as it is intended to be used
(as a `selector'). It is just that your example omits the identifier for
no purpose whatsoever.

Regards

Paul Bibbings
 
S

Saeed Amrollahi

There is no difference, C1 omits to give a name to something that
wouldn't be used in any case.

I suppose that those template declarations should result in the
declaration of the following two classes:

class C1 {

};

class C2 {

};

whatever the amount of different instantiations, but different
instantiations still are considered as different types, hence you will
not be able to assign a C1<double> to a C1<int> and thus I suppose the
compiler will create something like

class C1_int {

};

class C1_double {

};

or whatever other mechanism to disambiguate at runtime.

I can see uses of such a simple template (e.g. exception objects to be
thrown and caught on a per-template-parameter-type basis)




The former is a single declaration, where the A class doesn't exist
outside of B, the latter is a double declaration (two different
classes are declared and can be used separately).

At least that's what I understand about all of this, hope that helps.

I was out of office for a day.
Thank you for providing insight.
-- Saeed Amrollahi
 
S

Saeed Amrollahi

  There are situations where you want to declare (not define, but declare)
a template class. When you are doing such a declaration, you don't need the
template parameter for anything, and thus you can omit it.

  One practical situation where you may need to do that is when declaring
a template class to be a friend of another class (something which
surprisingly few C++ programmers know how to do). In other words, something
like:

    class A
    {
        template<typename> friend class B;
        ...
    };

  Here we are declaring that class B, which is a template class, is a
friend class of A. You could specify a name for the template parameter,
but since it's not used in the declaration, it can be omitted.

  Complete example:

#include <iostream>

class A
{
    template<typename> friend class B;
    int i;

 public:
    A(int value): i(value) {}

};

template<typename T>
class B
{
 public:
    void foo(const A& obj) { std::cout << obj.i << std::endl; }

};

int main()
{
    A a(5);
    B<int> b;
    b.foo(a);

}

Hi Juha
Sorry, for delay. I was out of office for a day.
It's cool application of unnamed template parameter.
Thank you for providing insight.
-- Saeed Amrollahi
 
S

Saeed Amrollahi

In your example as given there is no advantage.  For your first
definition you have parameterized A for no reason at all.  However, this
does not have any bearing on whether there /are/ reasons for which a
type may be parameterized where the name of the parameter is not used
*directly* in the definition of the class itself.

The following is perhaps not the best example, but hopefully illustrates
possible uses.  Here, the parameterization of select_on_type<> is used
to control which types of ShortOrIntOnly may be instantiated:

   template<class> struct select_on_type { };              // #1

   template<>
   struct select_on_type<short> {
      typedef short type;
   };

   template<>
   struct select_on_type<int> {
      typedef int type;
   };

   template<
      typename T,
      template <class> class Selector = select_on_type     // #2
   >
   struct ShortOrIntOnly {
      typename Selector<T>::type t;
   };

   int main()
   {
      ShortOrIntOnly<short> soi1;     // OK
      ShortOrIntOnly<int>   soi2;     // OK
      ShortOrIntOnly<char>  soi3;     // Error
   }

In the above code you will see a couple of places (#1 and #2) where it
is appropriate to use the syntax template<class> without requiring an
identifier for the template parameter.  The syntax, as used here, does
not detract from the purpose of the type as it is intended to be used
(as a `selector'). It is just that your example omits the identifier for
no purpose whatsoever.

Regards

Paul Bibbings

Hi Paul
Sorry, for delay. I was out of office for a day.
Thank you for providing detailed answer
-- Saeed Amrollahi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top