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