How to declare a pointer to a fucntion which (function's) return type can be different?

I have a class with a member data which is a pointer to a double function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//.h file

class A
{
  protected:
    double (*ptrToFucntion)( double );

  public:
    void SetFunction( string fName );
};

//.cpp file

void A::SetFunction( string fName )
{
  //depending on fName choose function
  ptrToFunction = &function;
}

But what if the return type of a function can differ from double. How to declare ptrToFunction then. I suspect that I should use a template but do not know exactly how.

NOTE: I do not want to variate the argument type. Only the return type.

For example, I want to do something like this:
1
2
3
4
5
6
7
8
9
10
inline int Floor( double x ) { return floor( x ); }
inline float Sin( double x ) { return sin( x ); }
inline double Exp( double x ) { return exp( x ); }

...

A a, b, c;
a.SetFunction( "Floor" );
b.SetFunction( "Sin" );
c.SetFunction( "Exp" );

Last edited on
You cannot specialize on return types.

(It is possible to cheat, but that is a design flaw.)

Return a double. The caller can then convert that to whatever it likes.

Hope this helps.
Did you mean doing something like:
 
inline double Floor( double x ) { return (double) floor( x ); }

?
By the way if I cannot specialize on return types, what do I do here when write:
1
2
3
4
5
template<typename T>
inline T Mimic( T x )
{
  return x;
}

And it works in this way well:
 
ptrToFunction = &Mimic<double>;
Last edited on
Not exactly what you where asking for, but perhaps can suggest a different strategy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// But what if the return type of a function can differ from double. How to 
// declare ptrToFunction then. I suspect that I should use a template but do 
// not know exactly how.
// NOTE: I do not want to variate the argument type. Only the return type.
#include <cmath>
#include <iostream>
#include <string>

class A {
protected:
    int myfloor (double val) { return static_cast<int>(std::floor(val)); }
    float mysin (double val) { return std::sin(val); }
    double myexp(double val) { return std::exp(val); }
    enum class Tag { RINT, RFLOAT, RDOUBLE };
    Tag rtype;
    union Horror {
        int myint;
        float myfloat;
        double mydouble;
    };
    Horror horror {};
public:
    void setFunction(std::string name)
    {
        if(name == "Floor") {
            rtype = Tag::RINT;
            return;
        }
        if(name == "Sin") {
            rtype = Tag::RFLOAT;
            return;
        }
        if(name == "Exp") {
            rtype = Tag::RDOUBLE;
            return;
        }
        std::cout << "\nWhat are you talking about, dude? I don't know "
                  << name << ".\n";
    }
    A& operator()(double val) {
        switch(rtype) {
        case Tag::RINT:
            horror.myint = myfloor(val);
            break;
        case Tag::RFLOAT:
            horror.myfloat = mysin(val);
            break;
        case Tag::RDOUBLE:
            horror.mydouble = myexp(val);
            break;
        }
        return *this;
    }
    friend std::ostream& operator<<(std::ostream& os, const A& a)
    {
        switch(a.rtype) {
        case Tag::RINT:
            os << a.horror.myint;
            break;
        case Tag::RFLOAT:
            os << a.horror.myfloat;
            break;
        case Tag::RDOUBLE:
            os << a.horror.mydouble;
            break;
        }
        return os;
    }
};

void waitForEnter();

int main()
{
    A a;
    a.setFunction("Floor");
    A b;
    b.setFunction("Sin");
    A c;
    c.setFunction("Exp");
    std::cout << "a(5.5): " << a(5.5) << '\n';
    std::cout << "b(5.5): " << b(5.5) << '\n';
    std::cout << "c(5.5): " << c(5.5) << '\n';
    waitForEnter();
    return 0;
}

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

By the way if I cannot specialize on return types, what do I do here when write:
1
2
3
4
5
template<typename T>
inline T Mimic( T x )
{
  return x;
}

And it works in this way well:
ptrToFunction = &Mimic<double>;

I think the compiler can still recognise the correct function by the argument types, not the return value. Does
1
2
3
template<typename T>
T Mimic(int x) { return “something which is a T”; }
ptrToFunction = &Mimic<double>;

work? I haven’t tried yet, sorry.
What an embarrassment but I cannot return "something which is a T" without initializing this. So I could try
 
return (T)x;

But I do not know if it will work.
Last edited on
You can't really do it. To see why, consider how you'd call it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
inline std::string f1() { return "hello"; }
inline double number() { return 1.1 }
inline std::ostream &stream() { return std::cout; }

...

A a;
if (condition1) {
    a.SetFunction( "string" );
} else if (condition2) {
    a.SetFunction( "number" );
} else {
    a.SetFunction( "stream" );

double d = a.ptrToFunction();  // what the heck should happen??? 

In this case the compiler can't figure out at compile time what is being returned and how, or even if, the return value can be converted to a double.
The problem runs deeper than that: you are basically asking the compiler to do magic What-Am-I? conversions with your data. You might as well throw out the type system.

On top of that, you are trying to create a pointer to a function without letting the compiler know anything about the function. How exactly is the compiler supposed to call that function? Again, you're asking for magic metadata bloat that the runtime has no need to know.

Return a double, and let the caller decide what to do with it.
Topic archived. No new replies allowed.