2

今天在编程语言理论课中,我们在 Java 中看到了这种行为:

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

在主要:

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

其中“令人难以置信”的是,该方法必须在 Integer 和 Float 之间选择参数类型 Y,并选择最接近的超类型,即 Number。

我想在 C++ 中重现它,但我被卡住了......

4

2 回答 2

4

模板不匹配时不会尝试调整类型。这就是为什么一个简单的实现如下:

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

失败并出现以下错误:

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')

你要做的是让函数模板同时接受这两种类型,然后解析通用类型:

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;
}

一个好主意是通过将类型推导提升到其签名中来使函数 SFINAE 友好:

template <class Y1, class Y2>
std::common_type_t<Y1, Y2> choose(Y1 y1, Y2 y2) {
    // Same as before
}
于 2017-04-20T09:43:20.593 回答
-1

使用模板函数。与您的 Java 代码执行相同操作的 C++ 代码实际上与 Java 代码本身非常相似:

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

你可以像在 Java 中那样简单地调用它——编译器会推断出正确的类型:

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

注意:在语义上,C++ 模板与 Java 泛型完全不同。Java 泛型是使用类型擦除实现的——JRE 在运行时不知道类型参数,而 C++ 模板实际上在每次模板用于不同类型时创建一个单独的函数或类。看到这个答案。

编辑:我误解了你的问题。不幸的是,我不相信 C++ 有你想要的行为。您必须明确指定两者都是超类型。

于 2017-04-20T09:33:01.603 回答