12

This code compiles:

std::string f(bool a, std::string const& b)
{
    if (a) return b;
    return {};
}

This code also compiles:

std::string f(bool a, std::string const& b)
{
    return a ? b : std::string{};
}

This code does not compile:

std::string f(bool a, std::string const& b)
{
    return a ? b : {};
}

Given that both result values of the ?: operator are required to be the same type, why doesn't it infer the type like it does in the first example?


It appears that this question might have a similar answer to this (which essentially boils down to "because nobody thought about it when writing the language specification"). However I still think it's useful to retain this question as the question itself is different, it's still sufficiently surprising, and the other wouldn't come up in searches for this issue.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Miral
  • 12,637
  • 4
  • 53
  • 93

1 Answers1

6

A braced initializer is not an expression and thus it has no type. See:

https://scottmeyers.blogspot.com/2014/03/if-braced-initializers-have-no-type-why.html

A braced initializer is a grammatical construct with special rules in the standard, explicitly specifying allowed use and type deduction. These special rules are needed exactly because braced initializers have no type. Using them in ?: statements is not specified, and thus the program is ill-formed.

If you really need to hear the man himself say it three times in a row before you believe it, then:

https://youtu.be/wQxj20X-tIU?t=1792

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
  • but `return {};` works – xaxxon May 15 '19 at 01:06
  • @xaxxon With `return {}` the return type of the function is known. – Nikos C. May 15 '19 at 01:07
  • with `return a ? b : {};` the return type of the function isn't known? – xaxxon May 15 '19 at 01:08
  • @xaxxon The return type is known, but the type of the `?:` isn't known. – Nikos C. May 15 '19 at 01:09
  • `return a ? b : "";` compiles, as does `return a ? b : std::initializer_list{};`. So clearly the compiler is allowed to perform construction/conversion based on the declared return type and/or the type of `b`. So `{}` should be equally valid. – Miral May 15 '19 at 01:13
  • 1
    @Miral `""` has a type. `std::initializer_list{}` also has a type. `{}` doesn't. – Nikos C. May 15 '19 at 01:14
  • Correct, but that means it's compatible with any type, which is how it works in return statements, arguments, and initialisation to begin with. – Miral May 15 '19 at 01:16
  • 2
    @Miral: "*it's compatible with any type*" No, it isn't. It is a grammatical construct which, in certain locations, can be used to initialize a prvalue of a type. It isn't "compatible" with anything. – Nicol Bolas May 15 '19 at 01:19
  • @Miral That's because the standard specifically allows for that. Braced initializers have no type, and thus their allowed use needs to be explicitly specified by the standard. Using it in `?:` was never specified and so the program is ill-formed. – Nikos C. May 15 '19 at 01:20
  • 2
    @NikosC.: It should be noted that braced-init-lists do not have a type because they're *not expressions*. They are a distinct grammatical construct from expressions. So asking them about type is like asking them about their "value" or any other thing associated with expressions. – Nicol Bolas May 15 '19 at 01:25
  • @xaxxon the language specification for the `return` statement explicitly says that the next thing can either be an expression, or a braced list, and goes on to define what will happen if a braced list is provided (namely, that the braced list is taken as initializer for copy-initialization of the result object) – M.M May 15 '19 at 04:18
  • 1
    I get that it's not a compiler error. But the other way to interpret the question is "does it actually make sense as a requirement?" or "is there a technical reason it cannot be done?" – xaxxon May 15 '19 at 05:01
  • As moderator stated "It appears that this question might have a similar answer to this (which essentially boils down to "because nobody thought about it when writing the language specification")." I don't see how it's duplicate. Nor I don't see reason it can't be done as type can be guessed from one of operands. – rAndom69 May 15 '19 at 15:42