Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ambiguous conversion for functional-style cast with complex<double>

I have a MVE program that compiles and runs with g++-5.2.0 but not with clang-602.0.53. The program tries to assign a lambda expression to a type alias of compatible type.

#include<iostream>
#include<complex>

using std::cout;
using std::endl;
using std::complex;
// type alias
using CfDD = complex<double> (*) (double);
// lambda of compatible type
auto theLambda = [] (double _) {return complex<double>({1,0});};

int main()
{   // Show that the lambda is callable:
    cout << theLambda(3.14) << endl;
    // Show that the lambda is assignable to a var of type CfDD
    CfDD cfdd = theLambda;
    cout << cfdd (3.14) << endl;
}

This program works when compiled with g++-5.2.0:

$ g++-5 --version
g++-5 (Homebrew gcc 5.2.0) 5.2.0
   ...
$ g++-5 -std=c++14 main.cpp && ./a.out
(1,0)
(1,0)

But produces an error that I don't understand and don't know how to fix under clang:

$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with- gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
    ...

$ gcc -std=c++14 main.cpp

main.cpp:10:40: error: ambiguous conversion for functional-style cast from 'void' to
  'complex<double>'
auto theLambda = [] (double _) {return complex<double>({1,0});};
                                       ^~~~~~~~~~~~~~~~~~~~~
    ...      candidate is the implicit move constructor
class _LIBCPP_TYPE_VIS_ONLY complex<double>
                            ^
    ...      candidate is the implicit copy constructor
candidate constructor
complex<double>::complex(const complex<float>& __c)

What does this error mean and why doesn't this code compile?

like image 531
Reb.Cabin Avatar asked Mar 14 '23 23:03

Reb.Cabin


1 Answers

When you wrote:

return complex<double>({1,0});

we look at the valid constructors for std::complex<double> and find:

constexpr complex(double re = 0.0, double im = 0.0); // (1)

constexpr complex( const complex& other ); // (2)

constexpr complex(const complex<float>& other); // (3a)
explicit constexpr complex(const complex<long double>& other); // (3b)

We're constructing this object with an initializer list. So (1) isn't viable, and neither is (3b) since that constructor is marked explicit. The other two, however, are both viable since both complex<double> and complex<float> can be constructed from two ints. Neither is better than the other, which is why clang complains about "ambiguous conversion".

The easiest solution is to drop the unnecessary {}s:

return complex<double>(1,0);

Note that you don't need to name the argument _, you can just not provide a name for it.

like image 184
Barry Avatar answered Apr 05 '23 22:04

Barry