【问题标题】:Using functions that return placeholder types defined in another translation unit使用返回在另一个翻译单元中定义的占位符类型的函数
【发布时间】:2015-03-01 00:56:30
【问题描述】:

我在理解 N3638 中描述的 auto 类型说明符的 C++14 扩展是如何实现的,以及究竟是什么是允许的。

具体来说,标准的更改之一是,

如果函数声明的返回类型包含占位符类型,则函数的返回类型是从函数体中的返回语句推导出来的。

当函数体与声明在同一个文件中时,很容易看出这是如何工作的;但考虑头文件使用auto 占位符声明方法但没有定义它的情况。包含此头文件但包含定义方法的文件的翻译单元如何才能成功编译?

例如,给定文件foo.hpp

class foo
{
  public:
    auto gen_data();
};

...和文件foo.cpp:

struct data_struct
{
  int a;
  int b;
  int c;
  double x;
  char data[37];
};

auto foo::gen_data()
{
  data_struct d;
  // initialize members in d...
  return d;
}

...和文件main.cpp:

#include "foo.hpp"

template<typename T>
double get_x(T f)
{
  return f.gen_data().x;
}

int make_and_get_x()
{
  foo f;
  return get_x<foo>(f);
}

...自己编译main.cpp 是否合法?如果不是,为什么不呢?如果是这样,get_x 是如何实例化的,因为编译器无法知道gen_data 的返回类型是否有一个名为x 的成员,更不用说它的偏移量是多少?

不过,即使不担心模板实例化,这似乎也是个问题;例如,如果您尝试直接访问 f.gen_data().x 或将其传递给函数会发生什么?

【问题讨论】:

  • 这是不合法的,因为编译器必须在每个需要它的翻译单元中推断返回类型(对于包含函数调用的表达式的类型)。但是,我不确定如何从标准中推断出来。

标签: c++ auto c++14 return-type-deduction translation-unit


【解决方案1】:

适用规则见 §7.1.6.4 [dcl.spec.auto]/p11:

如果需要具有未推断占位符类型的实体类型 要确定表达式的类型,程序是非良构的。

有一个例子:

auto f();
void g() { &f; }  // error, f’s return type is unknown

你需要gen_data的类型来确定表达式x.gen_data()的类型;因此该程序格式错误。要使用这样的函数,定义必须对编译器可见。

【讨论】:

  • 有什么可以证明推演需要“由编译器”/在需要返回类型的翻译单元中进行吗?那太好了。
  • 语言律师可以声称“返回类型已在另一个翻译单元中推导出来”。因此,我正在寻找“未演绎”的意思是“在当前翻译单元中未演绎”的内容。 (对于模板实例化,我认为 ODR 暗示了这一点。)
  • @dyp 嗯,我明白你的意思了。我认为我没有看到任何明确的说法......
  • 是的,@dyp 的“语言律师”问题或多或少是我想在我的问题中解决的问题。在链接时没有“未推断的占位符类型”之类的东西。 “未推导”必然意味着“在编译过程中的特定点未推导”。标准中是否有明确说明编译器何时需要能够推断出未推断占位符的真实类型的内容?
猜你喜欢
  • 1970-01-01
  • 2014-05-08
  • 1970-01-01
  • 2018-04-15
  • 1970-01-01
  • 2022-06-16
  • 2012-01-12
  • 2014-05-02
  • 1970-01-01
相关资源
最近更新 更多