在函数作用域内定义的类的引用

11

在C++1y中,函数的返回类型可以涉及到本地定义的类型:

auto foo(void) {
  class C {};
  return C();
}

类名Cfoo体外不在作用域内,因此您可以创建类实例,但不能指定其类型:

auto x            = foo(); // Type not given explicitly
decltype(foo()) y = foo(); // Provides no more information than 'auto'

有时候明确指定一个类型是很有必要的。也就是说,写下 "在foo中定义的类型C" 要比写 "foo返回的任何类型" 更有用。那么有没有办法明确地写出 foo 返回值的类型呢?


函数的返回类型推导在C++14中(希望)得到支持,但在C++11中不支持。 (在C++11中,它对于lambda表达式是支持的,但仅当主体是单个return语句时,因此您也无法在那里定义本地类型)。 - Mike Seymour
1
在块作用域声明的变量通常没有链接(3.5/8)。这意味着,根据定义,通过这些变量引用的实体不能在该作用域之外被命名。 - Igor Tandetnik
@MikeSeymour 谢谢,我没有意识到它不是 C++11 的一部分。我将 C++11 更改为 C++1y。 - Heatsink
1
你可以使用typedef/别名,如using foo_C = decltype(foo()); - dyp
@dyp,这是“foo返回的任何类型”,而不是“在foo中定义的类型C”。问题的答案是 - Jonathan Wakely
@JonathanWakely 没错,但是OP的意思有点含糊不清,可以看最后一句话。我同意你不能直接从外部作用域引用局部名称。 - dyp
1个回答

5
auto x            = foo(); // Type not given explicitly
decltype(foo()) y = foo(); // Provides no more information than 'auto'

那又怎样?你为什么在意类型的“真实”名称是什么?

就像dyp在评论中说的那样,如果你更喜欢使用typedef来给它命名,那么你可以这样做,而不是使用auto

 using foo_C = decltype(foo());

有时候,明确地指定类型是很有必要的。也就是说,写“在foo中定义的类型C”比写“foo返回的任何类型”更有用。有没有一种方法可以明确地写出foo返回值的类型?
没有。
就像没有这些作用域的名称一样,“foo()”内部的函数作用域也没有名称:
void bar()
{
  int i=0;
  // this scope does not have a name, cannot qualify `i`
  {
    int i=1;
    // this scope does not have a name, cannot qualify either `i`
  }
}

我关心类型的“真实”名称,因为我很难谈论我无法命名的事物。我想解释一下C++风格的迭代器库(例如Thrust)在类型推断期间执行类似于循环融合的操作。迭代器的类型记录将进入使用迭代器的循环中的所有代码。当类型无法完全书写时,这很难描述。 - Heatsink
你不需要知道“真实”的名称来谈论它,给它另一个名称即可。例如,你需要谈论 std::reverse_iterator<__gnu_cxx::__normal_iterator<std::vector<int>, int*>> 吗?还是使用 typedef std::vector<int>::reverse_iterator 更有用呢? - Jonathan Wakely
类型别名是有用的抽象。但有时候它们隐藏的东西很重要。为了理解涉及__gnu__cxx::__normal_iterator的编译时错误,您需要了解类型来自哪里。为了决定是否值得将Thrust缩减重写为CUDA内核,您需要考虑模板展开后代码的外观。您无法完全根据类型别名来理解它,因为类型推断和模板展开使用展开的类型。 - Heatsink

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接