如何在模板中返回正确的数据类型?


9
#include <iostream>
using namespace std;

template <class X, class Y>
Y big(X a, Y b)
{
   if (a > b)
      return (a);
   else return (b);
}

int main()
{
   cout << big(32.8, 9);
}

在这里,我在CPP中使用模板,因此,当我big绕过doubleand int类型的参数调用函数时,我希望返回的答案是double。这里的类型,它返回32而不是32.8

如何获得所需的输出?如何编写适当的返回类型的big函数?


1
一个函数只能返回一个固定类型。您无法在运行时选择返回哪种类型。
Jesper Juhl

1
您可能想看看如何std::max实现。在C ++中,必须在编译时就知道函数的返回类型。因此,您不能让此返回类型取决于参数的运行时值。这就是为什么要使用此函数,需要两个参数都具有相同的类型(即,具有X类型,但不具有Y类型)。
鲍里斯·达尔斯泰因

Answers:


12

一个函数只能有一个在编译时必须知道的返回类型。但是,可以使用std::common_type来返回可以将两个参数隐式转换为的类型。

那会是

#include <type_traits>
template <class X, class Y>
typename std::common_type<X,Y>::type big(X a, Y b)
{
   if (a > b)
      return a;
   else return b;
}

并检查它double在传递an int和a 时实际上返回a ,double我们可以这样做:

int main() {
    auto x = big(4.2,42);
    std::cout << std::is_same<decltype(x),double>::value;
}

哪些印刷品

1

PS:std::common_type可以在场景后面使用三元运算符,因此该解决方案与其他答案(auto+三元)并没有太大区别。的真正力量std::common_type在于它可以接受任意数量的参数。


10

返回类型必须在编译时确定。您可以使用尾随回条件运算符,如果仅限于

template <typename X, typename Y>
auto big(X&& a, Y&& b) -> decltype(a > b ? a : b) // ---> like this
{
   return  a > b ? a : b;
}

现场直播


但是,如果您可以访问 或更高的auto返回值就足够了,因为如果将它与条件运算符一起使用,则编译器将推断出正确的类型,如下所示:

template <typename X, typename Y>
auto big(X a, Y b)
{
   return  a > b ? a : b;
}

现场直播


至少从C ++ 14开始,不需要尾随返回类型。
中间人

@核桃好点。转发参考是另一种选择?
JeJo

1
@JeJo是的,我想这也很好,但可能毫无意义,因为您没有修改任何一个参数,并且无论哪种情况,返回类型仍将是左值引用(尽管可能不是const)。
胡桃

我删除了我的评论,因为它们不再适用了,但我建议在答案中添加一条警告,告知您不能使用参数按值。
胡桃

如果有人看您的代码,似乎传递的参数将决定某人将获得哪种返回类型,情况并非如此!即使a大于b,您也总是会获得双倍奖励。
克劳斯

4

在将返回类型标记为Y并将int第二个参数传递为时,您已经明确指出Yint。这里没有惊喜。

#include <iostream>

template <typename X, typename Y>
decltype(auto) big(const X& a, const Y& b)  // return type can just be auto as well 
{
    return a > b ? a : b;
}

int main()
{
    std::cout << big(32.8, 9) << '\n';
    std::cout << big(9, 32.8) << '\n';
    std::cout << big(32.8, 90) << '\n';
    std::cout << big(90, 32.8) << '\n';
}

这会将所有四个正确的值打印到屏幕上。

https://godbolt.org/z/fyGsmo

需要注意的一件事是,这仅适用于可以相互比较的类型,即,编译器将隐式将一种类型转换为另一种类型以进行比较。

重要说明:该参数需要通过引用来避免发生未定义的行为。这与我顽固地坚持的返回类型有关。decltype(auto)可以返回对类型的引用。如果返回函数的局部值(参数计数),则会得到未定义的行为。


@walnut意外返回引用比本网站说明的要难得多。但是很高兴知道未定义的行为。无论如何,这不是我会写的代码。这是一个问题的答案。
sweenish

1
啊。我读过您先前的评论是两个不同的观点,而不是效果和原因。我可以进行适当的编辑。
中间人

我添加了一个额外的免责声明。
中间人

2

这绝不是针对您的确切情况的正确解决方案-其他答案可能更接近您想要的。

但是,如果由于某种原因确实需要在运行时返回完全不同的类型,则正确的解决方案(因为)是使用std::variant,这是一种类型安全的联合。

#include <variant>

template <typename X, typename Y>
std::variant<X, Y> max(X a, Y b) {
  if (a > b)
    return std::variant<X, Y>(std::in_place_index_t<0>, a);
  else
    return std::variant<X, Y>(std::in_place_index_t<1>, b);
}

注意,调用者有责任处理返回的值,很可能使用std::visit或类似方法。


-2

它返回int,因为Y是一个int,并将32.8强制转换为int。当您调用big 32,82时,它是一个浮点数,而8是一个int且函数返回类型为Y,这也是一个int。

您无法真正解决此问题,因为您需要在运行时知道哪种类型的返回值很大,因此使a和b的类型相同,如下所示:

    #include <iostream>
    using namespace std;

    template <typename X>

    X big (X a, X b)
    {
    if (a>b)
    return a;

    else return b;
    }

    int main()
    {
    cout<< big (32.8, 9.0);
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.