Parametric methods with different subtypes

135 Views Asked by At

today in Theory of Programming Language class we have seen this behaviour in Java:

public class Es {
   ...
   <Y> Y choose(Y y1, Y y2){
         Y returnVal;
         if("some test"){ returnVal = y1;} else{ returnVal = y2;}
         return returnVal;
   }
}

In Main:

Es c = new Es();
Integer i = 3;
Float f = (float) 4.5;
Number n = c.choose(i, f);

Where the "incredible" is that the method must choose between Integer and Float for the parametric type Y and opts for the nearest super-type, which is Number.

I would like to reproduce this in C++ but I am stuck...

2

There are 2 best solutions below

0
Quentin On BEST ANSWER

Templates do not try adjusting types when they don't match. That's why a simple implementation like the following:

template <class Y>
Y choose(Y y1, Y y2) {
    // ...
}

Fails with the following error:

main.cpp:8:5: fatal error: no matching function for call to 'choose'
    choose(1, 2.5f);
    ^~~~~~
main.cpp:3:3: note: candidate template ignored:
                    deduced conflicting types for parameter 'Y' ('int' vs. 'float')

What you want to do is let the function template take in both types, then resolve the common type:

template <class Y1, class Y2>
auto choose(Y1 y1, Y2 y2) {
    using Y = std::common_type_t<Y1, Y2>;

    Y returnVal;

    if("some test") {
        returnVal = y1;
    } else {
        returnVal = y2;
    }

    return returnVal;
}

A good idea is to make the function SFINAE-friendly, by also lifting the type deduction into its signature:

template <class Y1, class Y2>
std::common_type_t<Y1, Y2> choose(Y1 y1, Y2 y2) {
    // Same as before
}
8
ostrichofevil On

Use a Template Function. The C++ code which does the same thing as your Java code is actually remarkably similar to the Java code itself:

template <typename Y>
Y choose(Y y1, Y y2) {
    Y returnVal;
    if("some test"){ returnVal = y1;} else{ returnVal = y2;}
    return returnVal;
}

You can simply call it as you would in Java—the compiler will infer the correct type:

choose(1,2); //With two ints
choose("hi","bye"); //With two char*s.

NOTE: Semantically, C++ templates are quite different from Java generics. Java generics are implemented using type erasure—the JRE has no idea of the type parameters at runtime, while C++ templates actually create a separate function or class each time the template is used for a different type. See this answer.

Edit: I misunderstood your question. Unfourtunately, I don't believe C++ has the behavior you want; you have to explicitly specify that both are the supertype.