看看这个:
template<class T>
struct X
{
private:
T value_;
public:
X():value_(T()) {}
X(T value):value_(value) {}
T getValue() const
{
return value_;
}
static const T value = 0; //this is dummy
template<class D, class U>
friend decltype(X<D>::value + X<U>::value) operator + (X<D> lhs, X<U> rhs);
};
template<class T, class U>
decltype(X<T>::value + X<U>::value) operator + (X<T> lhs, X<U> rhs)
{
return lhs.getValue() + rhs.getValue();
/* THIS COMPILES WITH VS2010 but line below doesn't which is incorrect
* behaviour in my opinion because: friendship has been declared and
* access to private data should be granted.*/
return lhs.value_ + rhs.value_; //THIS COMPILES WITH GCC 4.6
}
在这样的例子后,必须出现问题(顺便说一下整个例子编译并按预期工作),无论如何这里是问题:
我们真的必须使用晚期返回类型的哈巴狗丑陋语法吗?正如我在这个例子中证明的那样,它可以“正常的方式”完成。
编辑(现在没有这个可怕的静态假人 - 所有人都在唱着所有的舞蹈)
template<class T>
struct X
{
private:
T value_;
public:
typedef T value_type;
X():value_(T()) {}
X(T value):value_(value) {}
T getValue()const { return value_; }
template<class D, class U>
friend X<decltype(typename X<D>::value_type() + typename X<U>::value_type())> operator + (X<D> lhs, X<U> rhs);
};
template<class T, class U>
X<decltype(typename X<T>::value_type() + typename X<U>::value_type())> operator + (X<T> lhs, X<U> rhs)
{
return lhs.getValue() + rhs.getValue();
//return lhs.value_ + rhs.value_; //VS is __wrong__ not allowing this code to compile
}
答案 0 :(得分:3)
有时它在没有尾随返回类型的情况下不起作用,因为编译器无法知道程序员要求它做什么或涉及的类型是什么。
采用这个简单的转发包装模板函数(这不是一个简单的例子,而是取自我不久前写的一些真实代码):
template<typename T, typename... A> auto fwd(T fp, A...a) -> decltype(fp(a...))
{
// some other code
return fp(a...);
};
可以使用任何类型的未知返回类型的未知函数指针调用此函数。它会工作,它将返回正确的类型,并且不会混淆编译器。
如果没有尾随返回类型,编译器将无法确定发生了什么。
您可以使用#define
获得类似的效果并滥用逗号运算符,但只需付出代价即可。
答案 1 :(得分:3)
所有这些都缺少它添加的更好的可读性,而无需使用typedef或别名模板
auto f() -> void(*)();
将其与等效的
进行比较void (*f())();
您还可以在指定的返回类型中访问this
,但不能在早期返回类型中访问
class A {
std::vector<int> a;
public:
auto getVector() -> decltype((a));
auto getVector() const -> decltype((a));
};
如果您反过来使用它,它将无效,因为this
不在范围内,decltype((a))
两种时间都具有相同的类型(没有隐式{{1} }会被添加,因此this
的类型不会影响this
的类型。
答案 2 :(得分:2)
可以在没有decltype
的情况下完成,但这有一些缺点。您需要一个额外的模板参数,或者您需要依赖于添加两个类型为T
的项目的约定,以生成类型为T
的项目。
答案 3 :(得分:1)
如果我理解正确,你的意思是“迟到类型”
C ++ 11调用尾随返回类型的内容。在你的情况下
目前,没有问题,如果你不想使用
尾随返回类型,没有理由这样做。如果退货
type取决于参数类型,但是,它可以是非常的
详细说明必须在decltype
:
template <typename T1, typename T2>
auto add( T1 lhs, T2 rhs ) -> decltype( lhs + rhs );
要避免使用尾随返回类型,您必须编写 类似的东西:
template <typename T1, typename T2>
decltype( (*(T1*)0 + *(T2*)0 ) add( T1 lhs, T2 rhs );
第一个例子中的返回类型更加清晰,
如果参数类型更复杂(例如某些东西
比如std::vector<T1>
),它也更简洁:
template <typename T>
auto findInVector( std::vector<T> const& v ) -> decltype( v.begin() );
VS
template <typename T>
typename std::vector<T>::const_iterator
findInVector( std::vector<T> const& v );
答案 4 :(得分:1)
我没有得到这个问题,你问为什么语言允许你这样做:
template <typename T, typename U>
auto foo( X<T> lhs, X<U> rhs ) -> decltype( lhs + rhs );
而不是强制您人工将{x}}模板添加到静态虚拟成员,以便您输入:
X
真的?我的意思是,如果你愿意,可以使用其他不那么繁琐的结构,例如:
template <typename T, typename U>
decltype( X<T>::unneeded_artificial_static_member +
X<U>::unneeded_artificial_static_member )
foo( X<T> lhs, X<U> rhs ) -> decltype( lhs + rhs );
然后在需要时被迫使用template <typename T>
T& lvalue_of();
template <typename T, typename U>
decltype( lvalue_of< X<T> > + lvalue_of< X<U> > )
foo( X<T> lhs, X<U> rhs );
的特定变体:
lvalue_of
然后为template <typename T, typename U>
decltype( lvalue_of< X<T> > + lvalue_of< X<U> const > )
foo( X<T> lhs, X<U> const & rhs );
创建额外的变体...对于你可能会遇到的每个潜在用例,但为什么你更喜欢标准强迫你去那些奇怪的错误(你会记得吗?)更新rvalue_ref
如果更改参数?)构造来定义类型,当在参数声明后,编译器可以轻松地以安全简单的方式自行完成它?
通过这种推理,你也应该完全放弃语言中的lambda,它们根本不是一个启用功能。启用功能是能够在模板中使用本地类:
decltype
可以很容易地实现为:
std::function< void () > f = [](){ std::cout << "Hi"; };
然后你可能会想到很多其他功能可以从语言中轻易删除,因为有解决方法。
答案 5 :(得分:0)
以下是有用的延迟返回类型的示例。
#include <iostream>
#include <string>
using namespace std;
template <class T1>
auto inchesToFeet(int inch) -> T1
{
T1 inches = static_cast<T1>(inch);
T1 value = inches/12;
return value;
};
int _tmain(int argc, _TCHAR* argv[])
{
int inches = 29;
int approxWood = inchesToFeet<int>(inches);
cout << approxWood << " feet of wood" << endl;
float exactWire = inchesToFeet<float>(inches);
cout << exactWire << " feet of wire" << endl;
return 0;
}
Output:
2 feet of wood
2.41667 feet of wire