Doesn't constraining the "auto" in C++ defeat the purpose of it?

C++C++20AutoC++ ConceptsStd Integral

C++ Problem Overview


In C++20, we are now able to constrain the auto keyword to only be of a specific type. So if I had some code that looked like the following without any constraints:

auto something(){
  return 1;
}

int main(){
  const auto x = something();
  return x;
}

The variable x here is deduced to be an int. However, with the introduction of C++20, we can now constrain the auto to be a certain type like this:

std::integral auto something(){
  return 0;
}

int main(){
  const auto x = something();
  return x;
}

Doesn't this defeat the purpose of auto here? If I really need a std::integral datatype, couldn't I just omit the auto completely? Am I misunderstanding the use of auto completely?

C++ Solutions


Solution 1 - C++

A constraint on the deduced auto type doesn't mean it needs to be a specific type, it means it needs to be one of a set of types that satisfy the constraint. Note that a constraint and a type are not the same thing, and they're not interchangeable.

e.g. a concept like std::integral constrains the deduced type to be an integral type, such as int or long, but not float, or std::string.

> If I really need a std::integral datatype, couldn't I just omit the auto completely?

In principle, I suppose you could, but this would at the minimum lead to parsing difficulties. e.g. in a declaration like

foo f = // ...

is foo a type, or a constraint on the type?

Whereas in the current syntax, we have

foo auto f = // ...

and there's no doubt that foo is a constraint on the type of f.

Solution 2 - C++

> If I really need a std::integral datatype, couldn't I just omit the auto completely?

No, because std::integral is not a type, it's a concept, a constraint on types (or if you will, a set of types rather than a single type).

> Doesn't this defeat the purpose of auto here?

The original purpose of auto in C++11 is telling the compiler: Whatever type you deduce.*

With C++20, auto has an expanded use case - together with a concept, a constraint over types. auto still tells the compiler: Whatever type you deduce - but the deduction must also respect the constraint.

* - ignoring issues like constness, l/rvalue reference etc.

Solution 3 - C++

A concept often just move the error earlier in the compilation and makes code a bit more readable (since the concept name is a hint to the reader what you require from a type).

Rephrased:

It is rare you will ever use an auto variable in a way that it will work on every type.

For example:

auto fn(auto x) {
    return x++;
}

will not work if you do:

f(std::string("hello"));

because you can not increment std::string, the error is something like:

error: cannot increment value of type 'std::basic_string<char>'
    return x++;

If you change the function to:

auto fn(std::integral auto x) {
    return x++;
}

You will get an error like:

> :6:6: note: candidate template ignored: constraints not > satisfied [with x:auto = std::basic_string] auto > fn(std::integral auto x) {

For a small example this, it does not matter a lot, but for real code often the fn would call fn2 that calls fn3... and you would get the error deep in the std/boost/... implementation file.

So in this way concepts move the error to the site of the first function call.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionbeep_boopView Question on Stackoverflow
Solution 1 - C++cigienView Answer on Stackoverflow
Solution 2 - C++einpoklumView Answer on Stackoverflow
Solution 3 - C++NoSenseEtAlView Answer on Stackoverflow