Home > Blockchain >  C compiler says "inconsistent deduction for auto return type"
C compiler says "inconsistent deduction for auto return type"

Time:01-29

There is this nice feature in C where you can say the function has return type "auto" and compiler will figure it out. However, what if I return a pointer and nullptr on error? Somehow compiler then fails to deduce the correct type and gives an error.

In the following simple example imagine std::vector<int> is scheduled to be replaced by something else completely in future, to justify the use of auto here:

#include<vector>
std::vector<int> e;
auto test(){
  if(!e.empty())
    return &e[0];
  return nullptr;
}

In c 17 I get above error message.

So I tried replacing last return by

return reinterpret_cast<decltype(&e[0])>(nullptr)

and get the error invalid cast. Only solution I see is replacing that return by the 3 lines:

auto out=&e[0];
out=nullptr;
return out;

I probably could reduce that to 2 lines by replacing auto with some kind of decltype, but I imagine some other kind of cast could do what I want in a single line? Or do I need to use a newer version of the c standard for that case?

I also tried std::make_optional and get the same problem with nullopt_t being different type than std::optional. What I really would love is if compiler would automatically deduce type to be std::optional anyway...

CodePudding user response:

right, nullptr is type std::nullptr_t which is not type int*.

Static cast should be ok.

#include<vector>

std::vector<int> e;

auto test(){
  if(!e.empty())
    return &e[0];
  return static_cast<decltype(e.data())>(nullptr);
}

https://godbolt.org/z/sqfnqd69q

Even if reinterpret_cast worked (it doesn't), it would be overkill.


Regarding your follow up question, not sure what you want to achieve, but this seems close:

#include<vector>
#include<optional>

std::vector<int> e;

auto test(){
//  if(!e.empty())
//    return std::make_optional(e[0]);
//  return decltype(std::make_optional(e[0]))(std::nullopt);
    return e.empty()?std::nullopt:std::optional{e[0]};
}

I think this is more idiomatic:

#include<vector>

std::vector<int> e;

auto test(){
  if(!e.empty())
    return e.data();
  return static_cast<std::vector<int>::pointer>(nullptr);
}

I am a fan of auto, but this is one of the cases is better not to use it:

#include<vector>

std::vector<int> e;

auto test() -> std::vector<int>::pointer  // int*
{  
  if(!e.empty())
    return e.data();
  return nullptr;
}

CodePudding user response:

Just have one return.

auto test() {
  return e.empty() ? nullptr : &e[0];
}

you should explain the issue with OPs code

There are two returns with different type. Which type to choose?

and why this fixes it – 463035818_is_not_a_number

Because there are super long rules what type is the result of conditional operator. See https://en.cppreference.com/w/cpp/language/operator_other#Conditional_operator

  • Related