'Mixing constrained auto placeholder as non-trailing return type and explicit trailing return type

Can we mix constrained auto placeholder as non-trailing return type and trailing return type?

Demo

template<class T>
concept C = sizeof(T) > sizeof(char);

C auto g1(auto) -> int { return 1; }
C auto g2(auto) -> char { return '2'; }

int main() {
  return g1(0) + g2(0); 
}
  • GCC & MSVC: ok, returns 1 + '2', even if g2 returns a char
  • Clang: error with function with trailing return type must specify return type 'auto', not 'C auto'

I was expecting that

Concept auto foo(auto a, auto b) -> decltype(a + b)
{ return a + b; }

is equivalent to

auto foo(auto a, auto b) -> decltype(a + b)
    requires Concept<decltype(a + b)>
{ return a + b; }


Solution 1:[1]

They are not equivalent. First of all, correctly:

auto foo(auto a, auto b) -> Concept decltype(a + b) // or Concept auto
{ return a + b; }

it defines a foo function, which returns the type decltype(a + b), which is constrained by Concept. If it cannot, you get a compile time error.
The other:

auto foo(auto a, auto b) -> decltype(a + b)
    requires Concept<decltype(a + b)>
{ return a + b; }

will return a type of decltype(a + b), but this FUNCTION (not the retun type) is constrained to be valid only if decltype(a + b) fulfills the Concept, so if it doesn't you won't get any errors, since this function is cannot be used at all due to the requires clause.

For the 'Mixing' part of the question: With C auto g1(auto) -> int { return 1; }, you say something like "g1 will return some deduced type (auto) which must fulfill the C concept, and then you say return int. It is kinda weird. So you tell the compiler to deduce the type, then you explicitly say what type to return. I think it makes no sense...

Also the standard standard say that:

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

I don't find anything if the standard does not allow the C auto at the begining, but it explicitly defines that if you have a trailing-return type, the trailing-return type specifies the returned type, and not the placeholder auto.
So in GCC and MSVC it could be a bug, or they simply ignores that intentionally...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1