Search code examples
c++functionreturn-typeautotrailing-return-type

Clash between trailing return type and return type deduction


I'm writing some code where the return type of a function is rather complicated. I'd like to make use of auto for deducing from the return type, but that's obviously not possible in a forward declaration. So I was hoping to at least only duplicate the contents of the return statement and do the following,

int q = 5; // veeery complicated type

/* Declaration - the best we can do */
auto f() -> decltype(q);

/* Later, in a different file */    
auto f() {
  return q;
}

This produces the following error in GCC 7,

error: ambiguating new declaration of ‘auto f()’
note: old declaration ‘int f()’

Of course I could repeat

auto f() -> decltype(q) {
  return q;
}

in the definition (which works) but why should I need to when the return type is already uniquely given by the return statement? How is the type of f in my definition ultimately any more ambiguous than int f()?


Solution

  • The problem here is that a trailing return is not the same as purely deduced return type. In [dcl.spec.auto]/2

    [...]If the function declarator includes a trailing-return-type (8.3.5), that specifies the declared return type of the function

    So

    auto f() -> decltype(q);
    

    is really

    int f();
    

    which is different from

    auto f()
    

    There is also [dcl.spec.auto]/13

    Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type. [ Example:

    auto f();
    auto f() { return 42; }  // return type is int
    auto f();                // OK
    int f();                 // error, cannot be overloaded with auto f()
    decltype(auto) f();      // error, auto and decltype(auto) don’t match
    

    Which is kind of opposite of what is going on here but it does further exemplify that this is not allowed