我正在阅读有关“新”C ++功能的文本,并遇到了 decltype 及其用法。我理解跟踪返回类型
之类的 decltype 背后的原因template <typename lhsT, typename rhsT>
auto add(lhsT& lhs, rhsT& rhs) -> decltype(lhs + rhs) {
return lhs +rhs;
}
没有它,编译器将无法派生模板函数的返回类型。但为什么语法是这样的呢?
为什么不使用
之类的东西template <typename lhsT, typename rhsT>
decltype(lhs + rhs) add(lhsT& lhs, rhsT& rhs) {
return lhs +rhs;
}
因为返回类型通常在通常的位置被声明,所以会感觉更“自然”,尽管这是两个参数的结果。这是否与其他东西发生冲突或者是否会导致编译器的额外工作,如果语法是这样的,那是不值得的?
答案 0 :(得分:1)
编译器在引入符号之前很难引入符号。
template <typename lhsT, typename rhsT>
decltype(lhs + rhs) add(lhsT& lhs, rhsT& rhs) {
return lhs +rhs;
}
此处,<{1}}和lhs
在声明之前使用。
这很难做对。
rhs
这里它们在声明之后被使用。这很容易做对。
C ++,因为C ++ 11已经有意识地选择了解现有C ++编译器中的难点和易于实现的内容。在那里有很多C ++ 98/03功能很难实现,没有人真正做到,在某些情况下不可能(从.cpp文件发布模板,以及std :: string的一些要求,有两个)他们脱离了我的头顶。)
答案 1 :(得分:1)
没有它,编译器将无法派生模板函数的返回类型。
后来在C ++ 14中修复了它,并且编译器不需要尾随返回类型,因为它可以从返回的表达式推断返回类型。以下在C ++ 14中工作正常。
template <typename lhsT, typename rhsT>
auto add(const lhsT& lhs, const rhsT& rhs) {
return lhs + rhs;
}
但为什么语法是这样的呢?
当从参数中推断出返回类型时,使用尾随返回类型很有用,在返回类型之后总是声明(不能引用尚未声明的内容)尚未)。
此外,在函数和数学符号使用此类声明的意义上,尾随返回类型 似乎更自然。我认为C风格声明之外的大多数类型的符号通常使用尾随返回类型。 E.g :
f:X→Y
在上面的数学符号中,f
是函数名称,X
是参数,Y
是返回值。
只是因为一群粉红色的绵羊拒绝了灰色的绵羊并不会让它变得不自然。
在你的第二个例子中,编译器不可能推断返回类型,因为上述原因,即,参数尚未声明。但是,如果使用模板参数和std::declval
,,例如,则可以进行推理:
template <typename T, typename U>
decltype(std::declval<T>() + std::declval<U>()) add(const T& lhs, const U& rhs) {
return lhs + rhs;
}
std::declval
充当类型的惰性实例,从不评估,例如,调用构造函数等。它主要用于推断类型。