【问题标题】:Using auto and decltype to return reference from function in templated class使用 auto 和 decltype 从模板类中的函数返回引用
【发布时间】:2014-09-03 17:34:42
【问题描述】:

如何强制模板类中的函数使用 auto/decltype 返回对成员变量的引用?

这是我正在尝试做的一个简单的例子。假设你有一个模板类,它在私有成员变量a_ 中存储一些东西,如下所示:

#include <iostream>

template <typename T>
class A
{
private:
  T a_;

public:
  A(T a) : a_(a) {}

  // 1. Return const reference to a_
  const T & get() const { return a_; }

  // 2. Return non-const reference to a_
  T & get() { return a_; }
};

int main(int argc, char *argv[])
{
  A<int> a(3);

  const auto & a1 = a.get(); // 1. Return const reference to a_
  //a1 = 4;  // Shouldn't compile
  std::cout << "Value of a = " << a.get() << std::endl;

  auto & a2 = a.get(); // 2. Return non-const reference to a_
  a2 = 5;
  std::cout << "Value of a = " << a.get() << std::endl;

  return 0;
}

预期/期望的输出是:

Value of a = 3
Value of a = 5

但是现在,假设我希望编译器推断出 A&lt;T&gt; 中的 const 和非 const get() 函数返回的类型,并且我想确保两个调用都返回 references 到 @987654326 @。

我目前的最佳猜测是:

template <typename T>
class A
{
private:
  T a_;

public:
  A(T a) : a_(a) {}

  // 1. Return const reference to a_
  const auto get() const -> std::add_lvalue_reference<const decltype(a_)>::type
  {
    return a_;
  }

  // 2. Return non-const reference to a_
  auto get() -> std::add_lvalue_reference<decltype(a_)>::type
  {
    return a_;
  }
};

但是编译失败。 GCC给出的第一个错误是:

decltype.cpp:11:29: error: expected type-specifier
decltype.cpp:11:26: error: expected ‘;’ at end of member declaration
decltype.cpp:11:29: error: ‘add_lvalue_reference’ in namespace ‘std’ does not name a type

这样做的动机不在于我提炼的示例代码,而是源于试图减少模板采用的参数数量,当这些参数中的一个(或多个)仅用于指定编译器应该的返回类型时(我认为)能够自行推断。注意:在现实世界中,get() 的返回类型不是a_ 的返回类型,而是某个函数f(a_) 的返回类型,我知道它可以被编译器推导出来。因此在这个例子中我需要 auto/decltype。

让我感到困惑的是,编译器可以在非模板类中使用几乎相同的代码正确推断返回类型:

class A
{
private:
  int a_;

public:
  A(int a) : a_(a) {}

  // 1. Return const reference to a_
  const auto get() const -> std::add_lvalue_reference<const decltype(a_)>::type
  {
    return a_;
  }

  // 2. Return non-const reference to a_
  auto get() -> std::add_lvalue_reference<decltype(a_)>::type
  {
    return a_;
  }
};

任何帮助理解我所缺少的东西将不胜感激。

详情:

Centos 6.5
gcc (GCC) 4.7.2 20121015 (Red Hat 4.7.2-5)

【问题讨论】:

  • const auto get() const 对于尾随返回类型,您只能在函数名称前使用auto,而不是const auto
  • @Praetorian 我认为该段落并没有直接禁止使用const auto,因为它也适用于变量声明(auto 被替换)。但是,请查看 [dcl.fct]/2 明确禁止它
  • @jrok 8.3.5[dcl.fct]/p2 说“在声明 T D 中,D 的形式为 [带有尾随返回类型的函数声明语法],T 应成为单个类型说明符 auto。"
  • @Praetorian Well [dcl.spec.auto] 确实隐式允许 cv-qualifications; [dcl.fct]/2 需要使用trailing-return-type,不能与decltype(auto)结合使用。
  • 作为对任何访问者的澄清,const auto 在这种情况下无论如何都不需要;与使用 auto 的变量声明不同,函数自动 确实 维护 cv-qualification。

标签: c++ templates c++11 auto decltype


【解决方案1】:

顺便提一下,您实际上不必使用std::add_lvalue_reference 来获得您想要的行为。这同样有效,并且在我的书中更具可读性。

template <typename T>
class A {
    private:
        T a_; 

    public:
        A(T a) : a_(a) {}

        const auto get() const -> const decltype(a_) & {
            return a_; 
        }

        auto get() -> decltype(a_) & {
            return a_; 
        }
};

int main() {
    A<int> a(1);
    cout << a.get() << endl;
    a.get() = 2;
    cout << a.get() << endl;
}

【讨论】:

    【解决方案2】:

    a_ 包裹在尾随返回类型中的一对额外括号中,以获得表达式a_ 的类型,而不是变量a_ (Live at Coliru) 的声明类型:

    // 1. Return const reference to a_
    auto get() const -> decltype((a_))
    {
      return a_;
    }
    
    // 2. Return non-const reference to a_
    auto get() -> decltype((a_))
    {
      return a_;
    }
    

    或者如果C++1y is available:

    // 1. Return const reference to a_
    auto& get() const
    {
      return a_;
    }
    
    // 2. Return non-const reference to a_
    auto& get()
    {
      return a_;
    }
    

    【讨论】:

    • 如果你想返回一个常量引用,auto&amp; get() const { return a_; } 不应该是const auto&amp; get() const { return a_; } 吗?函数名后面的 const a 表示可以在其所属的常量对象上调用成员函数。
    • auto&amp; 可以很好地推断出对 const 类型的引用。 const auto&amp; 在这种情况下不会更正确,只会更明确。
    猜你喜欢
    • 1970-01-01
    • 2017-08-02
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    相关资源
    最近更新 更多