C++ 为什么我们必须有延迟返回类型?
看看这个:C++ 为什么我们必须有延迟返回类型?,c++,decltype,C++,Decltype,看看这个: 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<
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
}
模板
结构X
{
私人:
T值;
公众:
X():值(T()){
X(T值):值_uz(值){}
T getValue()常量
{
返回值;
}
static const T value=0;//这是虚拟的
模板
友元decltype(X::value+X::value)运算符+(X lhs,X rhs);
};
模板
decltype(X::value+X::value)运算符+(X左,X右)
{
返回lhs.getValue()+rhs.getValue();
/*这是用VS2010编译的,但下面的行没有,这是不正确的
*在我看来,这种行为是因为:友谊已经被宣布,并且
*应授予访问私人数据的权限*/
return lhs.value u+rhs.value;//这是用GCC 4.6编译的
}
在这样的例子之后,一定会有一个问题(通过整个例子按照预期编译和工作的方式),无论如何,问题是:
我们真的必须使用带有延迟返回类型的pug丑陋语法吗?正如我在本例中所证明的,它可以“以正常方式”完成
编辑(现在没有了这个可怕的静态假人-所有人都在唱歌,所有人都在跳舞)
模板
结构X
{
私人:
T值;
公众:
类型定义T值_类型;
X():值(T()){
X(T值):值_uz(值){}
T getValue()常量{返回值}
模板
友元X操作符+(X左,X右);
};
模板
X操作员+(X左,X右)
{
返回lhs.getValue()+rhs.getValue();
//返回lhs.value uu+rhs.value u;//VS是错误的uu不允许编译此代码
}
可以在不使用decltype
的情况下完成,但这有一些缺点。您需要一个额外的模板参数,或者您需要依赖于这样一种约定,即添加两个T
类型的项将生成一个T
类型的项,如果我理解正确,您的意思是“延迟返回类型”
C++11调用的尾部返回类型。如果你
现在,没有问题,如果你不想使用
尾随返回类型,没有理由这样做。如果返回
类型取决于参数类型,但是,它可能非常复杂
详细到必须在decltype
中重复它们:
template <typename T1, typename T2>
auto add( T1 lhs, T2 rhs ) -> decltype( lhs + rhs );
模板
自动添加(T1左侧,T2右侧)->取消类型(左侧+右侧);
为了避免使用尾随返回类型,您必须编写
比如:
template <typename T1, typename T2>
decltype( (*(T1*)0 + *(T2*)0 ) add( T1 lhs, T2 rhs );
模板
decltype((*(T1*)0+*(T2*)0)add(T1左侧,T2右侧);
在第一个示例中,返回类型更清楚,
如果参数类型更复杂(例如
与std::vector类似,它也更加简洁:
template <typename T>
auto findInVector( std::vector<T> const& v ) -> decltype( v.begin() );
模板
自动查找向量(std::vector const&v)->decltype(v.begin());
vs
模板
typename std::vector::const_迭代器
findInVector(std::vector const&v);
我不明白这个问题,你是在问为什么语言允许你这样做:
template <typename T, typename U>
auto 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 );
然后为rvalue\u ref
…为您可能遇到的每个潜在用例创建额外的变体,但究竟为什么您希望标准强制您使用这些奇怪的容易出错的变量(如果您更改参数,您会记得更新decltype
)构造来定义类型,在参数声明之后,编译器可以如此轻松地以安全的方式自己完成吗
根据这一推理,您还应该从语言中删除lambda,因为它们根本不是启用功能。启用功能能够在模板中使用本地类:
std::function< void () > f = [](){ std::cout << "Hi"; };
std::functionf=[](){std::cout有时,如果没有尾随的返回类型,它就无法工作,因为编译器无法知道程序员要求它做什么,或者所涉及的类型是什么
以这个简单的转发包装器模板函数为例(这不是虚构的示例,而是取自我不久前编写的一些真实代码):
template auto-fwd(T fp,A…A)->decltype(fp(A…)
{
//其他代码
返回fp(a…);
};
此函数可以使用任何类型的未知函数指针调用,该指针具有任何类型的未知返回类型。它将工作,它将返回正确的类型,并且不会混淆编译器
如果没有尾随返回类型,编译器将无法了解发生了什么
您可以使用#define
和滥用逗号运算符获得类似的效果,但是……代价是什么。所有这些都缺少它添加的更好的可读性,而不需要使用typedefs或别名模板
auto f() -> void(*)();
将其与等价物进行比较
void (*f())();
您还可以在后期指定的返回类型中访问此
,但不能在早期返回类型中访问
class A {
std::vector<int> a;
public:
auto getVector() -> decltype((a));
auto getVector() const -> decltype((a));
};
A类{
std::载体a;
公众:
auto getVector()->decltype((a));
auto getVector()const->decltype((a));
};
如果以另一种方式使用它,它将不起作用,因为此
不在范围内,decltype((a))
两次都具有相同的类型(不会添加隐式此
,因此此
的类型不会影响(a)
的类型).这里是一个有用的延迟返回类型示例
#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
#包括
#包括
使用名称空间std;
模板
自动英寸英尺(整数英寸)->T1
{
T1英寸=静态铸件(英寸);
T1值=英寸/12;
返回值;
};
int _tmain(int argc,_TCHAR*argv[]
{
整数英寸=29;
int approxWood=英寸英尺(英寸);
但我想说的唯一一点是,auto是不必要的,我们可以有正常的返回类型位置。仅此而已。@James如我在示例中所示,我不必以((T1)0+(T2)0)的形式编写帕格语法.@我们无能为力:您在示例中展示的是,如果您添加一个伪静态成员t,您可以更改@James使用的语法
struct lambda {
void operator()() {
std::cout << "Hi";
}
};
std::function< void () > f = lambda();
template<typename T, typename... A> auto fwd(T fp, A...a) -> decltype(fp(a...))
{
// some other code
return fp(a...);
};
auto f() -> void(*)();
void (*f())();
class A {
std::vector<int> a;
public:
auto getVector() -> decltype((a));
auto getVector() const -> decltype((a));
};
#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