具有不同子类型的参数化方法
Parametric methods with different subtypes
今天在编程语言理论 class 中我们已经在 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);
其中 "incredible" 是该方法必须在参数类型 Y 的 Integer 和 Float 之间进行选择,并选择最接近的超类型,即 Number。
我想用 C++ 重现这个,但我被卡住了...
使用 模板函数。 与 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++ 模板实际上创建一个单独的函数或 class 每次模板用于不同类型时。参见 this answer.
编辑: 我误解了你的问题。不幸的是,我不相信 C++ 有你想要的行为;您必须明确指定两者都是超类型。
模板不匹配时不会尝试调整类型。这就是为什么像下面这样的简单实现:
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
}
今天在编程语言理论 class 中我们已经在 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);
其中 "incredible" 是该方法必须在参数类型 Y 的 Integer 和 Float 之间进行选择,并选择最接近的超类型,即 Number。
我想用 C++ 重现这个,但我被卡住了...
使用 模板函数。 与 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++ 模板实际上创建一个单独的函数或 class 每次模板用于不同类型时。参见 this answer.
编辑: 我误解了你的问题。不幸的是,我不相信 C++ 有你想要的行为;您必须明确指定两者都是超类型。
模板不匹配时不会尝试调整类型。这就是为什么像下面这样的简单实现:
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
}