Using functions that return placeholder types defi

2019-02-18 13:15发布

问题:

I'm having some trouble understanding how the C++14 extension of the auto type-specifier described in N3638 can possibly be implemented, and what, exactly, is allowed.

Specifically, one of the changes to the standard says,

If the declared return type of the function contains a placeholder type, the return type of the function is deduced from return statements in the body of the function, if any.

It is easy enough to see how this works when body of the function is in the same file as the declaration; but consider the case where a header file declares a method using the auto placeholder but does not define it. How can translation units that include this header file but do not include the file that defines the method be successfully compiled?

For instance, given the file foo.hpp:

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

...and file 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;
}

...and file 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);
}

...is it legal to compile main.cpp on its own? If not, why not? If so, how is get_x instantiated, since there's no way for the compiler to know whether or not the return type of gen_data even has a member named x, let alone what its offset is?

This seems like it would be a problem even without worrying about template instantiation, though; for instance, what would happen if you tried accessing f.gen_data().x directly, or passing it to a function?

回答1:

The applicable rule is found in §7.1.6.4 [dcl.spec.auto]/p11:

If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed.

There's an example:

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

You need the type of gen_data to determine the type of the expression x.gen_data(); hence the program is ill-formed. To use such a function, the definition must be visible to the compiler.