Kafka
Kafka

Reputation: 820

auto deduction fails with message "inconsistent deduction for auto return type"

I have written the following test :

#include <cassert>
#include <iostream>
#include <string>
#include <cmath>
#include <functional>

// Works with std::function !
//std::function<double(double)> set_unary_operation(const std::string& unary)
auto set_unary_operation(const std::string& unary)
{
    if(unary == "EXP")
      return [](const double& x){ return std::exp(x);};
    if(unary == "LOG")
      return [](const double& x){ return std::log10(x);};
    if(unary == "_LN")
      return [](const double& x){ return std::log(x);};
    if(unary == "ABS")
      return [](const double& x){ return std::abs(x);};

    return [](const double& x){return x;};

}
  
bool is_equal(double&& value, double&& test)
{
    double epsilon = 0.0000001;
    return (value-epsilon < test) && (value+epsilon > test);
}

int main()
{
  // TEST OPERATOR --------------------------------------------------------------------------
  {
    std::string in = "EXP";

    auto f = set_unary_operation(in);

    std::cout << "f = EXP ; f(1) = "<< f(1) << "; f(2.5) = " << f(2.5) << std::endl;

    assert(is_equal(f(1)  , 2.71828182));
    assert(is_equal(f(2.5), 12.1824939607));
  }

  return 0;
}

The code works fine if I define the return type of set_unary_operation as std::function<double(double)>, but failed when I use auto with the following message :

error: inconsistent deduction for auto return type: ‘moteur_de_calcul::set_unary_operation(const string&)::<lambda(const double&)>’ and then ‘moteur_de_calcul::set_unary_operation(const string&)::<lambda(const double&)>’

I try to understand why the deduction failed (example can be found here : https://onlinegdb.com/Sk7bitBxD).

Upvotes: 2

Views: 760

Answers (2)

Waqar
Waqar

Reputation: 9366

A lambda is just a function object, and every lambda is unique. This is why set_unary_operation() fails. See the answer above by Songyuanyao for more details on this. There are multiple ways to get around this:

  • return std::function
  • return by casting to function pointer instead (wont work for lambdas that capture):
    return +[](const double& x){ return std::exp(x);};
  • Instead of creating a lambda for every case, you can check for the value of unary inside the lambda and change return value:
auto set_unary_operation(const std::string& unary)
{
    return [unary](const double& x)
    {
        if (unary == "EXP")
            return std::exp(x);
        if (unary == "LOG")
            return std::log10(x);
        //more cases..
    };
}
  • You can use templates...

Upvotes: 3

songyuanyao
songyuanyao

Reputation: 173004

Every lambda expression yields unique closure type,

The lambda expression is a prvalue expression of unique unnamed non-union non-aggregate class type, known as closure type, which is declared (for the purposes of ADL) in the smallest block scope, class scope, or namespace scope that contains the lambda expression.

which causes return type deduction fails because they are not same types.

If there are multiple return statements, they must all deduce to the same type

As you said you could specify std::function as the return type instead.

Upvotes: 5

Related Questions