Valid uses of template parameters

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dave Theese

    Valid uses of template parameters

    Please see questions in the code below... Thanks!

    #include <iostream>

    using namespace std;

    class foo_class
    {
    public:
    foo_class() {cout << "Constructing.. ." << endl;}
    ~foo_class() {cout << "Destructing... " << endl;}
    };

    template <typename T>
    void foo()
    {
    unsigned char mem[100];
    T *ptr;

    ptr = new(mem) T;

    ptr->~T(); // Funky destructor call - "concatenat ing" '~' with T's value.
    // In an overly-simplified sense, templates are a text
    // substitution mechanism, but this use of a template
    parameter is
    // different than what is usually seen. Is this really legal?
    }

    int main()
    {
    foo<foo_class>( ); // Outputs "Constructing.. .\nDestructing. ..\n"
    // Is my compiler exhibiting correct behavior? Should
    this
    // be legal (given what happens inside foo())?

    foo<int>(); // This works too! How is that happening? What does it mean
    to
    // "destruct" an int (which is what happens inside foo())???

    return 0;
    }



  • David B. Held

    #2
    Re: Valid uses of template parameters

    "Dave Theese" <cheeser_1998@y ahoo.com> wrote in message
    news:nMU6b.1384 3$QT5.2389@fed1 read02...[color=blue]
    > [...]
    > template <typename T>
    > void foo()
    > {
    > unsigned char mem[100];
    > T *ptr;
    >
    > ptr = new(mem) T;[/color]

    You'd better hope sizeof(T) <= 100, or else you should do
    this instead:

    template <typename T, int N = sizeof(T)>
    void foo()
    {
    unsigned char mem[N];
    // ...
    }
    [color=blue]
    > ptr->~T(); // Funky destructor call - "concatenat ing" '~'
    > // with T's value. In an overly-simplified
    > // sense, templates are a text substitution
    > // mechanism, but this use of a template
    > // parameter is different than what is usually
    > // seen. Is this really legal?[/color]

    Yes. That's the only way to explicitly name the d'tor when
    T is a parameterized type.
    [color=blue]
    > }
    >
    > int main()
    > {
    > foo<foo_class>( ); // Outputs "Constructing.. .\nDestructing. ..\n"
    > // Is my compiler exhibiting correct behavior?
    > // Should this be legal (given what happens
    > // inside foo())?[/color]

    As far as I know that is the expected behaviour. However,
    there is the technicality that mem in foo() is not guaranteed
    to be correctly aligned for T. That may lead to undefined
    behaviour.
    [color=blue]
    > foo<int>(); // This works too! How is that happening?
    > // What does it mean to "destruct" an int (which
    > // is what happens inside foo())???
    >
    > return 0;
    > }[/color]

    Well, one would expect that the d'tor for POD types would
    be trivial, so it most probably means "do nothing". And
    the reason you are able to call ~T() for [T = int] is precisely
    to aid generic programming. Note that you can't call
    ~int().

    Dave



    Comment

    • Dave Theese

      #3
      Re: Valid uses of template parameters


      "David B. Held" <dheld@codelogi cconsulting.com > wrote in message
      news:bjh811$lg6 $1@news.astound .net...[color=blue]
      > "Dave Theese" <cheeser_1998@y ahoo.com> wrote in message
      > news:nMU6b.1384 3$QT5.2389@fed1 read02...[color=green]
      > > [...]
      > > template <typename T>
      > > void foo()
      > > {
      > > unsigned char mem[100];
      > > T *ptr;
      > >
      > > ptr = new(mem) T;[/color]
      >
      > You'd better hope sizeof(T) <= 100, or else you should do
      > this instead:
      >
      > template <typename T, int N = sizeof(T)>
      > void foo()
      > {
      > unsigned char mem[N];
      > // ...
      > }
      >[color=green]
      > > ptr->~T(); // Funky destructor call - "concatenat ing" '~'
      > > // with T's value. In an overly-simplified
      > > // sense, templates are a text substitution
      > > // mechanism, but this use of a template
      > > // parameter is different than what is usually
      > > // seen. Is this really legal?[/color]
      >
      > Yes. That's the only way to explicitly name the d'tor when
      > T is a parameterized type.
      >[color=green]
      > > }
      > >
      > > int main()
      > > {
      > > foo<foo_class>( ); // Outputs "Constructing.. .\nDestructing. ..\n"
      > > // Is my compiler exhibiting correct behavior?
      > > // Should this be legal (given what happens
      > > // inside foo())?[/color]
      >
      > As far as I know that is the expected behaviour. However,
      > there is the technicality that mem in foo() is not guaranteed
      > to be correctly aligned for T. That may lead to undefined
      > behaviour.
      >[color=green]
      > > foo<int>(); // This works too! How is that happening?
      > > // What does it mean to "destruct" an int (which
      > > // is what happens inside foo())???
      > >
      > > return 0;
      > > }[/color]
      >
      > Well, one would expect that the d'tor for POD types would
      > be trivial, so it most probably means "do nothing". And
      > the reason you are able to call ~T() for [T = int] is precisely
      > to aid generic programming. Note that you can't call
      > ~int().
      >
      > Dave
      >
      >
      >[/color]

      Yep, the alignment issues that you and Kevin raised are, of course, valid.
      I was just trying to make the example as simplistic as possible to try and
      focus attention on the ~type() issue. Well, this is all quite interesting.
      I suppose it's somewhat analagous to T() being well-defined, even for
      built-in types. Thank you both!!!


      Comment

      • Dave Theese

        #4
        Re: Valid uses of template parameters


        "David B. Held" <dheld@codelogi cconsulting.com > wrote in message
        news:bjh811$lg6 $1@news.astound .net...[color=blue]
        > "Dave Theese" <cheeser_1998@y ahoo.com> wrote in message
        > news:nMU6b.1384 3$QT5.2389@fed1 read02...[color=green]
        > > [...]
        > > template <typename T>
        > > void foo()
        > > {
        > > unsigned char mem[100];
        > > T *ptr;
        > >
        > > ptr = new(mem) T;[/color]
        >
        > You'd better hope sizeof(T) <= 100, or else you should do
        > this instead:
        >
        > template <typename T, int N = sizeof(T)>
        > void foo()
        > {
        > unsigned char mem[N];
        > // ...
        > }
        >[color=green]
        > > ptr->~T(); // Funky destructor call - "concatenat ing" '~'
        > > // with T's value. In an overly-simplified
        > > // sense, templates are a text substitution
        > > // mechanism, but this use of a template
        > > // parameter is different than what is usually
        > > // seen. Is this really legal?[/color]
        >
        > Yes. That's the only way to explicitly name the d'tor when
        > T is a parameterized type.
        >[color=green]
        > > }
        > >
        > > int main()
        > > {
        > > foo<foo_class>( ); // Outputs "Constructing.. .\nDestructing. ..\n"
        > > // Is my compiler exhibiting correct behavior?
        > > // Should this be legal (given what happens
        > > // inside foo())?[/color]
        >
        > As far as I know that is the expected behaviour. However,
        > there is the technicality that mem in foo() is not guaranteed
        > to be correctly aligned for T. That may lead to undefined
        > behaviour.
        >[color=green]
        > > foo<int>(); // This works too! How is that happening?
        > > // What does it mean to "destruct" an int (which
        > > // is what happens inside foo())???
        > >
        > > return 0;
        > > }[/color]
        >
        > Well, one would expect that the d'tor for POD types would
        > be trivial, so it most probably means "do nothing". And
        > the reason you are able to call ~T() for [T = int] is precisely
        > to aid generic programming. Note that you can't call
        > ~int().
        >
        > Dave
        >
        >
        >[/color]

        On looking a little closer, the proposal of a function template default
        argument value won't work, as such defaults are allowed only in class
        tempaltes. But the point is well-taken!


        Comment

        • Dave Theese

          #5
          Re: Valid uses of template parameters

          "David B. Held" <dheld@codelogi cconsulting.com > wrote in message
          news:bjh811$lg6 $1@news.astound .net...[color=blue]
          > "Dave Theese" <cheeser_1998@y ahoo.com> wrote in message
          > news:nMU6b.1384 3$QT5.2389@fed1 read02...[color=green]
          > > [...]
          > > template <typename T>
          > > void foo()
          > > {
          > > unsigned char mem[100];
          > > T *ptr;
          > >
          > > ptr = new(mem) T;[/color]
          >
          > You'd better hope sizeof(T) <= 100, or else you should do
          > this instead:
          >
          > template <typename T, int N = sizeof(T)>
          > void foo()
          > {
          > unsigned char mem[N];
          > // ...
          > }
          >[color=green]
          > > ptr->~T(); // Funky destructor call - "concatenat ing" '~'
          > > // with T's value. In an overly-simplified
          > > // sense, templates are a text substitution
          > > // mechanism, but this use of a template
          > > // parameter is different than what is usually
          > > // seen. Is this really legal?[/color]
          >
          > Yes. That's the only way to explicitly name the d'tor when
          > T is a parameterized type.
          >[color=green]
          > > }
          > >
          > > int main()
          > > {
          > > foo<foo_class>( ); // Outputs "Constructing.. .\nDestructing. ..\n"
          > > // Is my compiler exhibiting correct behavior?
          > > // Should this be legal (given what happens
          > > // inside foo())?[/color]
          >
          > As far as I know that is the expected behaviour. However,
          > there is the technicality that mem in foo() is not guaranteed
          > to be correctly aligned for T. That may lead to undefined
          > behaviour.
          >[color=green]
          > > foo<int>(); // This works too! How is that happening?
          > > // What does it mean to "destruct" an int (which
          > > // is what happens inside foo())???
          > >
          > > return 0;
          > > }[/color]
          >
          > Well, one would expect that the d'tor for POD types would
          > be trivial, so it most probably means "do nothing". And
          > the reason you are able to call ~T() for [T = int] is precisely
          > to aid generic programming. Note that you can't call
          > ~int().
          >
          > Dave
          >
          >
          >[/color]

          And as long as we're at it, is there concurrence that the following will
          eliminate the alignment / size issues raised by Kevin and Dave about my
          original example? I plan on archiving this example, so I should get it
          right in all respects...


          #include <iostream>

          using namespace std;

          class foo_class
          {
          public:
          foo_class() {cout << "Constructing.. ." << endl;}
          ~foo_class() {cout << "Destructing... " << endl;}
          };

          template <typename T>
          void foo()
          {
          void *mem;
          T *ptr;

          mem = operator new(sizeof(T));
          ptr = new(mem) T;
          ptr->~T();
          operator delete(mem);
          }

          int main()
          {
          foo<foo_class>( );
          foo<int>();

          return 0;
          }


          Comment

          • Kevin Goodsell

            #6
            Re: Valid uses of template parameters

            Dave Theese wrote:

            (In the future please trim when replying. We don't need 500-lines of
            irrelevant text tagged onto a reply.)
            [color=blue]
            >
            > And as long as we're at it, is there concurrence that the following will
            > eliminate the alignment / size issues raised by Kevin and Dave about my
            > original example? I plan on archiving this example, so I should get it
            > right in all respects...
            >
            >
            > #include <iostream>
            >
            > using namespace std;
            >
            > class foo_class
            > {
            > public:
            > foo_class() {cout << "Constructing.. ." << endl;}
            > ~foo_class() {cout << "Destructing... " << endl;}
            > };
            >
            > template <typename T>
            > void foo()
            > {
            > void *mem;
            > T *ptr;
            >
            > mem = operator new(sizeof(T));[/color]

            I strongly suspect that this will solve the alignment problem (in
            practice), but I'm not 100% sure. I'm even less sure that the standard
            requires it to work. I only know of one method that I am completely sure
            will work, and that is to use malloc() or calloc() to allocate the memory.

            There are other methods that are likely to work (the most common being
            to define a union object containing several different types of objects,
            the goal being to force it to have the strictest possible alignment
            requirements), but they are considerably more complicated.
            [color=blue]
            > ptr = new(mem) T;
            > ptr->~T();
            > operator delete(mem);
            > }
            >
            > int main()
            > {
            > foo<foo_class>( );
            > foo<int>();
            >
            > return 0;
            > }
            >
            >[/color]

            -Kevin
            --
            My email address is valid, but changes periodically.
            To contact me please use the address from a recent posting.

            Comment

            • David B. Held

              #7
              Re: Valid uses of template parameters

              "Dave Theese" <cheeser_1998@y ahoo.com> wrote in message
              news:AXV6b.1385 0$QT5.1578@fed1 read02...[color=blue]
              > [...]
              > And as long as we're at it, is there concurrence that the
              > following will eliminate the alignment / size issues raised
              > by Kevin and Dave about my original example? I plan on
              > archiving this example, so I should get it right in all
              > respects...
              > [...]
              > template <typename T>
              > void foo()
              > {
              > void *mem;
              > T *ptr;
              >
              > mem = operator new(sizeof(T));
              > ptr = new(mem) T;
              > ptr->~T();
              > operator delete(mem);
              > }
              > [...][/color]

              I know that an array of char returned from new is
              guaranteed to have proper alignment for any type
              that is the size of the array. I'm not sure if an
              operator new call provides the same guarantee or
              not, because my copy of the standard is not handy
              right now, and I'm too lazy to look it up. I would
              assume that memory returned from operator new
              would have suitable alignment, or else it wouldn't
              be very useful.

              Dave



              Comment

              Working...