template for function pointer

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • firegun9@yahoo.com.tw

    template for function pointer

    Hello everyone,
    here is my program:

    ///////////////////////////////
    #include <iostream>
    using namespace std;

    void multi(double* arrayPtr, int len){
    for(int i=0; i<len; i++)
    *(arrayPtr+i)*= 2;
    }
    typedef void (*p2f) (double* a, int b);
    //////////////////////////////
    template <class T>
    class bf{
    private:
    int type;
    T var;
    public:
    bf(int i, T value){ type=i; var=value;}
    void eval(double* dPtr, int len);
    };

    template <class T>
    void bf<T>::eval(dou ble* dPtr, int len){
    switch(type){
    case 0:
    for(int i=0; i<len; i++)
    *(dPtr+i)=var;
    break;
    case 1:
    for(int i=0; i<len; i++)
    *(dPtr+i)=*(var +i);
    break;
    case 2:
    var(dPtr, len);
    break;
    }
    }

    void main(){
    double a=0.0;
    bf<double> a1(0,a);

    double b[3]={0.0, 1.0, 2.0};
    bf<double*> a2(1,b);

    bf<p2f> a3(2,multi);

    double temp[3]={5.0, 5.0, 5.0};
    a1.eval(temp,3) ;
    for(int i=0;i<3;i++)
    cout<<temp[i]<<endl;
    }

    I have a bf class with a member variable "var" whose type is defined as
    a template. In bf's constructor, I use (int type) to record what type
    var is defined.
    The main purpose of bf is to retrieve a double array, then modified it
    using the var member.
    By different types of var, it does different modifies to the input
    array.

    There are 3 conditions:
    If var is a double( it can be known from "type" variable), it fill the
    incoming array with the double value.
    If var is a double array, it copies its value one by one into the
    incoming array.
    If var is a function pointer, it takes the incoming array as the
    argument.

    There's no problem untill I call bf::eval() in main();
    It seems like that if var is a double then the code "var(dPtr, len);"
    is wrong. In fact, it is wrong. But that is in case 2. Whenever the var
    is not a function pointer, it will never go into case 2 in the switch
    in eval();
    The familiar situation also happens when the var is set to a function
    pointer. The error was found in case 0, in which var is treated as a
    double.

    I just wanna control the branch call by myself.
    Is there any solution?
    Thanks

  • Thomas Wintschel

    #2
    Re: template for function pointer


    <firegun9@yahoo .com.tw> wrote in message
    news:1104616356 .358972.83090@z 14g2000cwz.goog legroups.com...[color=blue]
    > Hello everyone,
    > here is my program:
    >
    > ///////////////////////////////
    > #include <iostream>
    > using namespace std;
    >
    > void multi(double* arrayPtr, int len){
    > for(int i=0; i<len; i++)
    > *(arrayPtr+i)*= 2;
    > }
    > typedef void (*p2f) (double* a, int b);
    > //////////////////////////////
    > template <class T>
    > class bf{
    > private:
    > int type;
    > T var;
    > public:
    > bf(int i, T value){ type=i; var=value;}
    > void eval(double* dPtr, int len);
    > };
    >[/color]

    Generally, you use a template when you want to apply the same code
    structure to different types. Your problem here is that you are trying
    to apply different code depending on the type which fails because you
    cannot provide a T that has all the necessary properties.
    [color=blue]
    > template <class T>
    > void bf<T>::eval(dou ble* dPtr, int len){
    > switch(type){
    > case 0:
    > for(int i=0; i<len; i++)
    > *(dPtr+i)=var;[/color]

    In order for this line to compile, it must be possible to convert T to a
    double.
    [color=blue]
    > break;
    > case 1:
    > for(int i=0; i<len; i++)
    > *(dPtr+i)=*(var +i);[/color]

    In order for this line to compile, it must be possible to convert T to a
    double*.
    [color=blue]
    > break;
    > case 2:
    > var(dPtr, len);[/color]

    In order for this line to compile,
    T must have a constructor that takes a double* and an int.
    [color=blue]
    > break;
    > }
    > }
    >[/color]

    So, if you want the preceding method to compile, you need to use a T for
    which the following statements are all valid:

    T t1;
    double d = t1;
    double* p = t1;
    T t2(p, 1);
    [color=blue]
    > void main(){
    > double a=0.0;
    > bf<double> a1(0,a);
    >
    > double b[3]={0.0, 1.0, 2.0};
    > bf<double*> a2(1,b);
    >
    > bf<p2f> a3(2,multi);
    >
    > double temp[3]={5.0, 5.0, 5.0};
    > a1.eval(temp,3) ;
    > for(int i=0;i<3;i++)
    > cout<<temp[i]<<endl;
    > }
    >
    > I have a bf class with a member variable "var" whose type is defined[/color]
    as[color=blue]
    > a template. In bf's constructor, I use (int type) to record what type
    > var is defined.
    > The main purpose of bf is to retrieve a double array, then modified it
    > using the var member.
    > By different types of var, it does different modifies to the input
    > array.
    >
    > There are 3 conditions:
    > If var is a double( it can be known from "type" variable), it fill the
    > incoming array with the double value.
    > If var is a double array, it copies its value one by one into the
    > incoming array.
    > If var is a function pointer, it takes the incoming array as the
    > argument.
    >
    > There's no problem untill I call bf::eval() in main();
    > It seems like that if var is a double then the code "var(dPtr, len);"
    > is wrong. In fact, it is wrong. But that is in case 2. Whenever the[/color]
    var[color=blue]
    > is not a function pointer, it will never go into case 2 in the switch
    > in eval();
    > The familiar situation also happens when the var is set to a function
    > pointer. The error was found in case 0, in which var is treated as a
    > double.
    >
    > I just wanna control the branch call by myself.
    > Is there any solution?
    > Thanks
    >[/color]

    I will ignore other obvious, dangerous errors in your code since I think
    you are really misguided in trying to do what you are doing.

    Some advice:

    First read some more about C++ and object-oriented programming. You are
    trying to treat numerical, pointer and function pointer types like they
    are the same thing when they are very different creatures.

    Read much more about templates. In particular, take a look at STL type
    requirements, which specify the properties a type must have in order to
    be used with a particular template. A vector, for instance, requires
    that T be 'Assignable' meaning that you can write:
    T a;
    T b = a;

    Perhaps if you state what higher level problem you are trying to solve
    you will get some useful advice. In the meantime, remember that
    templates will only work with types that have something in common.

    Merry New Year
    Tom


    Comment

    • Bruce Trask

      #3
      Re: template for function pointer

      Hi Thomas,

      The problem you are seeing is that the compiler is trying to compile all
      three branches of the case statement *for each type of the template
      parameter* and all those branches are not valid of all the template
      parameters you are using.

      I am going to throw some code at you that perhaps solves you requirements in
      different way. Have a look at it. It probably introduces some new concepts
      but these concepts lend themselve more correctly to solving the type of
      problem you are trying to solve.

      ///////////////////////////////////////

      #include <vector>
      #include <algorithm>
      #include <iterator>
      #include <iostream>

      using namespace std;

      double doubleArray[] = { 1.0, 2.0, 3.0 };
      const size_t sz = 3;


      double doubleArrayTwo[] = { 5.0, 6.0, 7.0 };
      const size_t sz2 = 3;

      double func(const double elem)
      {
      return elem*2;
      }
      int main()
      {
      vector<double> myDoubleVec(&do ubleArray[0],
      &doubleArray[3]);

      // case 1
      double val = 5;

      fill(myDoubleVe c.begin(),
      myDoubleVec.end (),
      5);

      // print the result
      copy(myDoubleVe c.begin(),
      myDoubleVec.end (),
      ostream_iterato r<double>(cout, "\n"));

      // case 2

      copy(&doubleArr ayTwo[0],
      &doubleArray Two[sz2],
      myDoubleVec.beg in());

      // print the result
      copy(myDoubleVe c.begin(),
      myDoubleVec.end (),
      ostream_iterato r<double>(cout, "\n"));

      // case 3
      transform(myDou bleVec.begin(),
      myDoubleVec.end (),
      myDoubleVec. begin(),
      func);

      copy(myDoubleVe c.begin(),
      myDoubleVec.end (),
      ostream_iterato r<double>(cout, "\n"));

      return 0;
      }
      ///////////////////////////////////////////////////////////////////////
      Let me know how it goes.

      Regards,
      Bruce


      <firegun9@yahoo .com.tw> wrote in message
      news:1104616356 .358972.83090@z 14g2000cwz.goog legroups.com...[color=blue]
      > Hello everyone,
      > here is my program:
      >
      > ///////////////////////////////
      > #include <iostream>
      > using namespace std;
      >
      > void multi(double* arrayPtr, int len){
      > for(int i=0; i<len; i++)
      > *(arrayPtr+i)*= 2;
      > }
      > typedef void (*p2f) (double* a, int b);
      > //////////////////////////////
      > template <class T>
      > class bf{
      > private:
      > int type;
      > T var;
      > public:
      > bf(int i, T value){ type=i; var=value;}
      > void eval(double* dPtr, int len);
      > };
      >
      > template <class T>
      > void bf<T>::eval(dou ble* dPtr, int len){
      > switch(type){
      > case 0:
      > for(int i=0; i<len; i++)
      > *(dPtr+i)=var;
      > break;
      > case 1:
      > for(int i=0; i<len; i++)
      > *(dPtr+i)=*(var +i);
      > break;
      > case 2:
      > var(dPtr, len);
      > break;
      > }
      > }
      >
      > void main(){
      > double a=0.0;
      > bf<double> a1(0,a);
      >
      > double b[3]={0.0, 1.0, 2.0};
      > bf<double*> a2(1,b);
      >
      > bf<p2f> a3(2,multi);
      >
      > double temp[3]={5.0, 5.0, 5.0};
      > a1.eval(temp,3) ;
      > for(int i=0;i<3;i++)
      > cout<<temp[i]<<endl;
      > }
      >
      > I have a bf class with a member variable "var" whose type is defined as
      > a template. In bf's constructor, I use (int type) to record what type
      > var is defined.
      > The main purpose of bf is to retrieve a double array, then modified it
      > using the var member.
      > By different types of var, it does different modifies to the input
      > array.
      >
      > There are 3 conditions:
      > If var is a double( it can be known from "type" variable), it fill the
      > incoming array with the double value.
      > If var is a double array, it copies its value one by one into the
      > incoming array.
      > If var is a function pointer, it takes the incoming array as the
      > argument.
      >
      > There's no problem untill I call bf::eval() in main();
      > It seems like that if var is a double then the code "var(dPtr, len);"
      > is wrong. In fact, it is wrong. But that is in case 2. Whenever the var
      > is not a function pointer, it will never go into case 2 in the switch
      > in eval();
      > The familiar situation also happens when the var is set to a function
      > pointer. The error was found in case 0, in which var is treated as a
      > double.
      >
      > I just wanna control the branch call by myself.
      > Is there any solution?
      > Thanks
      >[/color]



      Comment

      • Bruce Trask

        #4
        Re: template for function pointer

        Sorry, my response was not to Thomas but to the original poster.


        "Bruce Trask" <b_trask@yahoo. com> wrote in message
        news:AuKBd.1846 9$152.17240@trn dny01...[color=blue]
        > Hi Thomas,
        >
        > The problem you are seeing is that the compiler is trying to compile all
        > three branches of the case statement *for each type of the template
        > parameter* and all those branches are not valid of all the template
        > parameters you are using.
        >
        > I am going to throw some code at you that perhaps solves you requirements[/color]
        in[color=blue]
        > different way. Have a look at it. It probably introduces some new[/color]
        concepts[color=blue]
        > but these concepts lend themselve more correctly to solving the type of
        > problem you are trying to solve.
        >
        > ///////////////////////////////////////
        >
        > #include <vector>
        > #include <algorithm>
        > #include <iterator>
        > #include <iostream>
        >
        > using namespace std;
        >
        > double doubleArray[] = { 1.0, 2.0, 3.0 };
        > const size_t sz = 3;
        >
        >
        > double doubleArrayTwo[] = { 5.0, 6.0, 7.0 };
        > const size_t sz2 = 3;
        >
        > double func(const double elem)
        > {
        > return elem*2;
        > }
        > int main()
        > {
        > vector<double> myDoubleVec(&do ubleArray[0],
        > &doubleArray[3]);
        >
        > // case 1
        > double val = 5;
        >
        > fill(myDoubleVe c.begin(),
        > myDoubleVec.end (),
        > 5);
        >
        > // print the result
        > copy(myDoubleVe c.begin(),
        > myDoubleVec.end (),
        > ostream_iterato r<double>(cout, "\n"));
        >
        > // case 2
        >
        > copy(&doubleArr ayTwo[0],
        > &doubleArray Two[sz2],
        > myDoubleVec.beg in());
        >
        > // print the result
        > copy(myDoubleVe c.begin(),
        > myDoubleVec.end (),
        > ostream_iterato r<double>(cout, "\n"));
        >
        > // case 3
        > transform(myDou bleVec.begin(),
        > myDoubleVec.end (),
        > myDoubleVec. begin(),
        > func);
        >
        > copy(myDoubleVe c.begin(),
        > myDoubleVec.end (),
        > ostream_iterato r<double>(cout, "\n"));
        >
        > return 0;
        > }
        > ///////////////////////////////////////////////////////////////////////
        > Let me know how it goes.
        >
        > Regards,
        > Bruce
        >
        >
        > <firegun9@yahoo .com.tw> wrote in message
        > news:1104616356 .358972.83090@z 14g2000cwz.goog legroups.com...[color=green]
        > > Hello everyone,
        > > here is my program:
        > >
        > > ///////////////////////////////
        > > #include <iostream>
        > > using namespace std;
        > >
        > > void multi(double* arrayPtr, int len){
        > > for(int i=0; i<len; i++)
        > > *(arrayPtr+i)*= 2;
        > > }
        > > typedef void (*p2f) (double* a, int b);
        > > //////////////////////////////
        > > template <class T>
        > > class bf{
        > > private:
        > > int type;
        > > T var;
        > > public:
        > > bf(int i, T value){ type=i; var=value;}
        > > void eval(double* dPtr, int len);
        > > };
        > >
        > > template <class T>
        > > void bf<T>::eval(dou ble* dPtr, int len){
        > > switch(type){
        > > case 0:
        > > for(int i=0; i<len; i++)
        > > *(dPtr+i)=var;
        > > break;
        > > case 1:
        > > for(int i=0; i<len; i++)
        > > *(dPtr+i)=*(var +i);
        > > break;
        > > case 2:
        > > var(dPtr, len);
        > > break;
        > > }
        > > }
        > >
        > > void main(){
        > > double a=0.0;
        > > bf<double> a1(0,a);
        > >
        > > double b[3]={0.0, 1.0, 2.0};
        > > bf<double*> a2(1,b);
        > >
        > > bf<p2f> a3(2,multi);
        > >
        > > double temp[3]={5.0, 5.0, 5.0};
        > > a1.eval(temp,3) ;
        > > for(int i=0;i<3;i++)
        > > cout<<temp[i]<<endl;
        > > }
        > >
        > > I have a bf class with a member variable "var" whose type is defined as
        > > a template. In bf's constructor, I use (int type) to record what type
        > > var is defined.
        > > The main purpose of bf is to retrieve a double array, then modified it
        > > using the var member.
        > > By different types of var, it does different modifies to the input
        > > array.
        > >
        > > There are 3 conditions:
        > > If var is a double( it can be known from "type" variable), it fill the
        > > incoming array with the double value.
        > > If var is a double array, it copies its value one by one into the
        > > incoming array.
        > > If var is a function pointer, it takes the incoming array as the
        > > argument.
        > >
        > > There's no problem untill I call bf::eval() in main();
        > > It seems like that if var is a double then the code "var(dPtr, len);"
        > > is wrong. In fact, it is wrong. But that is in case 2. Whenever the var
        > > is not a function pointer, it will never go into case 2 in the switch
        > > in eval();
        > > The familiar situation also happens when the var is set to a function
        > > pointer. The error was found in case 0, in which var is treated as a
        > > double.
        > >
        > > I just wanna control the branch call by myself.
        > > Is there any solution?
        > > Thanks
        > >[/color]
        >
        >
        >[/color]


        Comment

        • Bruce Trask

          #5
          Re: template for function pointer

          Aside from taking a different approach with the STL, you had a question as
          to how to make the compiler avoid some branches in the code. The answer to
          that would be to provide template specializations for the eval member
          function. This gives you what amounts to a compile time switch. See the
          code below to see how this works. It has the added benefit of failing at
          link time if anyone uses a type that you have not provided a specialization
          for.

          #include <iostream>
          using namespace std;

          void multi(double* arrayPtr, int len){
          for(int i=0; i<len; i++)
          *(arrayPtr+i)*= 2;
          }
          typedef void (*p2f) (double* a, int b);
          //////////////////////////////
          template <class T>
          class bf{
          private:
          int type;
          T var;
          public:
          bf(int i, T value){ type=i; var=value;}
          void eval(double* dPtr, int len);
          };

          template <>
          void bf<double>::eva l(double* dPtr, int len){
          cout << "1" << endl;
          for(int i=0; i<len; i++)
          *(dPtr+i)=var;
          }

          template <>
          void bf<double*>::ev al(double* dPtr, int len){
          cout << "2" << endl;
          for(int i=0; i<len; i++)
          *(dPtr+i)=*(var +i);
          }

          template <>
          void bf<p2f>::eval(d ouble* dPtr, int len){
          cout << "3" << endl;
          var(dPtr, len);
          }

          int main(){
          double a=0.0;
          bf<double> a1(0,a);

          double b[3]={0.0, 1.0, 2.0};
          bf<double*> a2(1,b);

          bf<p2f> a3(2,multi);

          double temp[3]={5.0, 5.0, 5.0};
          cout << "calling eval" << endl;
          a1.eval(temp,3) ;
          for(int i=0;i<3;i++)
          cout<<temp[i]<<endl;
          }

          Hope that helps,
          Bruce

          "Bruce Trask" <b_trask@yahoo. com> wrote in message
          news:6wKBd.1042 7$sh5.8053@trnd ny08...[color=blue]
          > Sorry, my response was not to Thomas but to the original poster.
          >
          >
          > "Bruce Trask" <b_trask@yahoo. com> wrote in message
          > news:AuKBd.1846 9$152.17240@trn dny01...[color=green]
          > > Hi Thomas,
          > >
          > > The problem you are seeing is that the compiler is trying to compile all
          > > three branches of the case statement *for each type of the template
          > > parameter* and all those branches are not valid of all the template
          > > parameters you are using.
          > >
          > > I am going to throw some code at you that perhaps solves you[/color][/color]
          requirements[color=blue]
          > in[color=green]
          > > different way. Have a look at it. It probably introduces some new[/color]
          > concepts[color=green]
          > > but these concepts lend themselve more correctly to solving the type of
          > > problem you are trying to solve.
          > >
          > > ///////////////////////////////////////
          > >
          > > #include <vector>
          > > #include <algorithm>
          > > #include <iterator>
          > > #include <iostream>
          > >
          > > using namespace std;
          > >
          > > double doubleArray[] = { 1.0, 2.0, 3.0 };
          > > const size_t sz = 3;
          > >
          > >
          > > double doubleArrayTwo[] = { 5.0, 6.0, 7.0 };
          > > const size_t sz2 = 3;
          > >
          > > double func(const double elem)
          > > {
          > > return elem*2;
          > > }
          > > int main()
          > > {
          > > vector<double> myDoubleVec(&do ubleArray[0],
          > > &doubleArray[3]);
          > >
          > > // case 1
          > > double val = 5;
          > >
          > > fill(myDoubleVe c.begin(),
          > > myDoubleVec.end (),
          > > 5);
          > >
          > > // print the result
          > > copy(myDoubleVe c.begin(),
          > > myDoubleVec.end (),
          > > ostream_iterato r<double>(cout, "\n"));
          > >
          > > // case 2
          > >
          > > copy(&doubleArr ayTwo[0],
          > > &doubleArray Two[sz2],
          > > myDoubleVec.beg in());
          > >
          > > // print the result
          > > copy(myDoubleVe c.begin(),
          > > myDoubleVec.end (),
          > > ostream_iterato r<double>(cout, "\n"));
          > >
          > > // case 3
          > > transform(myDou bleVec.begin(),
          > > myDoubleVec.end (),
          > > myDoubleVec. begin(),
          > > func);
          > >
          > > copy(myDoubleVe c.begin(),
          > > myDoubleVec.end (),
          > > ostream_iterato r<double>(cout, "\n"));
          > >
          > > return 0;
          > > }
          > > ///////////////////////////////////////////////////////////////////////
          > > Let me know how it goes.
          > >
          > > Regards,
          > > Bruce
          > >
          > >
          > > <firegun9@yahoo .com.tw> wrote in message
          > > news:1104616356 .358972.83090@z 14g2000cwz.goog legroups.com...[color=darkred]
          > > > Hello everyone,
          > > > here is my program:
          > > >
          > > > ///////////////////////////////
          > > > #include <iostream>
          > > > using namespace std;
          > > >
          > > > void multi(double* arrayPtr, int len){
          > > > for(int i=0; i<len; i++)
          > > > *(arrayPtr+i)*= 2;
          > > > }
          > > > typedef void (*p2f) (double* a, int b);
          > > > //////////////////////////////
          > > > template <class T>
          > > > class bf{
          > > > private:
          > > > int type;
          > > > T var;
          > > > public:
          > > > bf(int i, T value){ type=i; var=value;}
          > > > void eval(double* dPtr, int len);
          > > > };
          > > >
          > > > template <class T>
          > > > void bf<T>::eval(dou ble* dPtr, int len){
          > > > switch(type){
          > > > case 0:
          > > > for(int i=0; i<len; i++)
          > > > *(dPtr+i)=var;
          > > > break;
          > > > case 1:
          > > > for(int i=0; i<len; i++)
          > > > *(dPtr+i)=*(var +i);
          > > > break;
          > > > case 2:
          > > > var(dPtr, len);
          > > > break;
          > > > }
          > > > }
          > > >
          > > > void main(){
          > > > double a=0.0;
          > > > bf<double> a1(0,a);
          > > >
          > > > double b[3]={0.0, 1.0, 2.0};
          > > > bf<double*> a2(1,b);
          > > >
          > > > bf<p2f> a3(2,multi);
          > > >
          > > > double temp[3]={5.0, 5.0, 5.0};
          > > > a1.eval(temp,3) ;
          > > > for(int i=0;i<3;i++)
          > > > cout<<temp[i]<<endl;
          > > > }
          > > >
          > > > I have a bf class with a member variable "var" whose type is defined[/color][/color][/color]
          as[color=blue][color=green][color=darkred]
          > > > a template. In bf's constructor, I use (int type) to record what type
          > > > var is defined.
          > > > The main purpose of bf is to retrieve a double array, then modified it
          > > > using the var member.
          > > > By different types of var, it does different modifies to the input
          > > > array.
          > > >
          > > > There are 3 conditions:
          > > > If var is a double( it can be known from "type" variable), it fill the
          > > > incoming array with the double value.
          > > > If var is a double array, it copies its value one by one into the
          > > > incoming array.
          > > > If var is a function pointer, it takes the incoming array as the
          > > > argument.
          > > >
          > > > There's no problem untill I call bf::eval() in main();
          > > > It seems like that if var is a double then the code "var(dPtr, len);"
          > > > is wrong. In fact, it is wrong. But that is in case 2. Whenever the[/color][/color][/color]
          var[color=blue][color=green][color=darkred]
          > > > is not a function pointer, it will never go into case 2 in the switch
          > > > in eval();
          > > > The familiar situation also happens when the var is set to a function
          > > > pointer. The error was found in case 0, in which var is treated as a
          > > > double.
          > > >
          > > > I just wanna control the branch call by myself.
          > > > Is there any solution?
          > > > Thanks
          > > >[/color]
          > >
          > >
          > >[/color]
          >
          >[/color]


          Comment

          Working...