从输入参数具体用例推导出的尾随 return 类型
Trailing return type deduced from input arguments concrete use-case
我看到使用尾随 return 类型的原因之一是当我们想从输入参数中推断出 return 类型时。
我知道还有其他原因,但我在这个问题中重点关注这个具体原因。
给出的示例之一是:
template <typename T>
auto func(const T & t) -> decltype(std::cout << t)
{
return std::cout << t;
}
但我想不出任何具体的用例。
我的意思是,我们在编写函数时总是知道函数的 return 类型,当从参数推导出 return 类型实际上是 [=30 时,我找不到任何具体示例=]需要和无法避免。
我们总是可以(如果我没记错的话)通过直接指定 return 类型而不进行任何推导来重写函数的原型,这在我看来更简洁明了。
上面的例子可以改写为:
template <typename T>
std::ostream& func(const T & t)
{
return std::cout << t;
}
在我看来,这比尾随 return 类型的版本更简洁,更易读。
我错过了什么?
The above example can be rewritten as:
不,不能。您的结论是基于以下假设:
std::ostream& operator<<(std::ostream&,const T&);
但事实并非如此。可能是
any_other_type operator<<(std::ostream&,const T&);
那么您的方法版本将无法编译,而推导出 return 类型的版本则可以。
对于具体的用例,考虑某种 io 操作,让您编写代码,例如
std::cout << all_caps_modifier << "some text" << back_to_normal_modifier << " more text";
那将打印:
SOME TEXT more text
我承认这是一个相当人为的例子,但是使用一些封装 std::cout
并使字符串以大写字母打印的代理是实现它的一种可能方法( std::cout << all_caps_modifier
会 return 不同于 std::ostream&
) 的类型。
I mean, we always know the return type of a function when we write it
我们呢?所以如果你写这个函数模板:
template<typename A, typename B>
/* ret */ foo(A a, B b) {
return a + b;
}
你能确定ret
是什么吗?如果给定两个整数,那么它肯定是一个整数。但是,如果提供一个整数和一个长整数,由于促销,它应该是长整数。如果一个参数是双精度数,那么结果应该是双精度数。
如果那是某些 class 类型的两个对象呢?现在我们正在调用一个重载的 operator+
,绝对没有人会猜测它可能 return.
我希望你现在相信我们接受 任何 两种类型,我们不能总是确定涉及这些类型的表达式的类型。
于是在语言中加入了一种机制来告诉。诚然,此示例过于简单,可能会被 auto
return 类型取代,但一般原则仍然存在。在编写泛型代码时,我们经常会处理未知类型。几乎不知道涉及它们的表达式的类型应该是什么,或者即使这样的表达式在 在 函数被实例化之前是有效的。 decltype
告诉我们。
我看到使用尾随 return 类型的原因之一是当我们想从输入参数中推断出 return 类型时。
我知道还有其他原因,但我在这个问题中重点关注这个具体原因。
给出的示例之一是:
template <typename T>
auto func(const T & t) -> decltype(std::cout << t)
{
return std::cout << t;
}
但我想不出任何具体的用例。
我的意思是,我们在编写函数时总是知道函数的 return 类型,当从参数推导出 return 类型实际上是 [=30 时,我找不到任何具体示例=]需要和无法避免。
我们总是可以(如果我没记错的话)通过直接指定 return 类型而不进行任何推导来重写函数的原型,这在我看来更简洁明了。
上面的例子可以改写为:
template <typename T>
std::ostream& func(const T & t)
{
return std::cout << t;
}
在我看来,这比尾随 return 类型的版本更简洁,更易读。
我错过了什么?
The above example can be rewritten as:
不,不能。您的结论是基于以下假设:
std::ostream& operator<<(std::ostream&,const T&);
但事实并非如此。可能是
any_other_type operator<<(std::ostream&,const T&);
那么您的方法版本将无法编译,而推导出 return 类型的版本则可以。
对于具体的用例,考虑某种 io 操作,让您编写代码,例如
std::cout << all_caps_modifier << "some text" << back_to_normal_modifier << " more text";
那将打印:
SOME TEXT more text
我承认这是一个相当人为的例子,但是使用一些封装 std::cout
并使字符串以大写字母打印的代理是实现它的一种可能方法( std::cout << all_caps_modifier
会 return 不同于 std::ostream&
) 的类型。
I mean, we always know the return type of a function when we write it
我们呢?所以如果你写这个函数模板:
template<typename A, typename B>
/* ret */ foo(A a, B b) {
return a + b;
}
你能确定ret
是什么吗?如果给定两个整数,那么它肯定是一个整数。但是,如果提供一个整数和一个长整数,由于促销,它应该是长整数。如果一个参数是双精度数,那么结果应该是双精度数。
如果那是某些 class 类型的两个对象呢?现在我们正在调用一个重载的 operator+
,绝对没有人会猜测它可能 return.
我希望你现在相信我们接受 任何 两种类型,我们不能总是确定涉及这些类型的表达式的类型。
于是在语言中加入了一种机制来告诉。诚然,此示例过于简单,可能会被 auto
return 类型取代,但一般原则仍然存在。在编写泛型代码时,我们经常会处理未知类型。几乎不知道涉及它们的表达式的类型应该是什么,或者即使这样的表达式在 在 函数被实例化之前是有效的。 decltype
告诉我们。