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?
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.
Related
I'm getting the following error
min.cpp:17:30: error: no viable conversion from '<overloaded function type>' to 'Container::UnaryFun' (aka 'function<double (double)>')
this->addFunction("abs", abs);
when trying to compile the following code:
#include <cmath>
#include <string>
#include <functional>
class Test
{
public:
using UnaryFun = std::function<double (double)>;
Test()
{
this->addFunction("abs", abs);
}
auto addFunction(const std::string& name, UnaryFun fun) -> void
{
// ...
}
};
auto main() -> int {
Test eval;
return 0;
}
I've tried to check the declaration of std::abs for argument double and return type double and looks like this:
inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
return __builtin_fabs(__lcpp_x);
}
in /usr/local/Cellar/llvm/15.0.7_1/include/c++/v1/stdlib.h.
It is accesible specifically for the double type. I've checked this by adding:
double a = 5;
double b = std::abs(a);
and this compiles without problems or conversion warnings.
I've tried to declare my own abs function like so:
inline double xabs(double val)
{
return val < 0 ? -val : val;
}
and then change the following code like so to use this new xabs instead of std::abs
this->addFunction("abs", xabs);
and after this change, the code compiles.
Any ideas why the code with std::abs doesn't compile?
My environment:
OS: Mac OS 12.6
Compiler:
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Command to compile: g++ -std=c++2a -o min min.cpp
Update based on comments
I dug a bit deeper, and it seems that there is a problem with how std::function is declared, which led to the problem above.
If I declare addFunction like so, without std::function, the problem disappears.
auto addFunction(const std::string& name, double (*fun)(double)) -> void
{
}
This means that the compiler cannot figure out the matching abs if std::function is used but it can identify the matching overload if the type of the function is described directly without std::function.
The problem is that, since it has multiple overloads, std::abs doesn't have a single type. That means that the compiler can't select a std::function constructor to use to convert it since it can't deduce a type for the constructor's template parameter.
There are a couple of ways to get around that:
Use a cast:
addFunction("abs", std::static_cast<double(*)(double)>(std::abs));
Wrap it in a lambda:
addFunction("abs", [](double d) { return std::abs(d); });
As you've done, wrap it in a non-overloaded function
#include <iostream>
struct Index {
constexpr operator int() const { return 666; }
};
template <int i> void foo() {
std::cout << i << std::endl;
}
void wrapper(Index index) {
foo<index>();
}
int main() {
Index index;
// foo<index>(); // error: the value of ‘index’ is not usable in a constant expression
wrapper(index);
}
Hello, everyone.
I'm using a constexpr conversion of a variable "index" to an int value, which is substituted to a "foo" templated function.
If I directly call foo<index>() from "main", I get a compiler error.
If the same call is done from the "wrapper", then everything compiles and works fine.
What am I missing there?
Compile command: g++ -std=c++14 main.tex with g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6).
A very similar error was reported here. It was first reported with GCC 4.9.0
In the analysis provided:
This is a GCC bug. It appears to be some sort of confusion in the way GCC handles internal linkage non-type template parameters of pointer type.
It has since been resolved.
I went to see if you could use auto in a variable template declaration.
template <typename T>
auto F = T{};
Fine, but as soon as you try to use it, clang craps.
int f = F<int>; // error: cannot initialize a variable of type 'int' with an lvalue of type 'auto'
auto f = F<int>; // Stacktrace
decltype(F<int>) f = F<int>; // StackFace
std::cout << std::is_same<int, decltype(F<int>)>::value; // false
std::cout << typeid(decltype(F<int>)).name(); // Stacktrace
std::cout << std::is_same<decltype(F<int>), decltype(F<int>)>::value; // true
Any combination of decltype(auto), auto doesn't work even though it says that auto is an lvalue.
int f = static_cast<int>(F<int>); // error: static_cast from 'auto' to 'int' is not allowed
I've never seen auto act this way before. Is it because of variable templates or because of how clang treats auto?
This seems to be addressed in the latest version of clang; putting that into a file and calling
clang++ -std=c++1y test.cpp
gives me no errors.
kevinushey#Kevin-MBP:~$ clang++ -v
clang version 3.5 (trunk 201469)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
Here is the source code that can be used to reproduce the issue:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/move/move.hpp>
#include <boost/ref.hpp>
std::ostream& dump_to_stream(std::ostream& os, int a, int b) {
return os << a << '\n' << b << '\n';
}
template <class R, class F>
R call_under_lock(F f) {
// lock();
R r = f();
// unlock();
return boost::move(r);
}
int main() {
std::ostream& os = call_under_lock<std::ostream&>(
boost::bind(&dump_to_stream, boost::ref(std::cout), 1, 2));
}
When using C++03 mode in GCC the code compiles without any problems. On the other hand the use of C++0x mode produces the following error:
$ g++ -I../../boost_latest -std=c++0x -O2 -Wall -Wextra -c -o test.o test.cpp
(...)
test.cpp: In function ‘R call_under_lock(F) [with R = std::basic_ostream<char>&, F = boost::_bi::bind_t<std::basic_ostream<char>&, std::basic_ostream<char>& (*)(std::basic_ostream<char>&, int, int), boost::_bi::list3<boost::reference_wrapper<std::basic_ostream<char> >, boost::_bi::value<int>, boost::_bi::value<int> > >]’:
test.cpp:20:62: instantiated from here
test.cpp:15:23: error: invalid initialization of non-const reference of type ‘std::basic_ostream<char>&’ from an rvalue of type ‘boost::remove_reference<std::basic_ostream<char>&>::type {aka std::basic_ostream<char>}’
(...)
What is the reason of such a failure? Is there a way to workaround it in C++11 mode?
The code presented above is a simplification of what I use in a generic code. Hence the need for such a combination (boost::move + non-const ref as a return value type).
I use gcc v4.6.3, Boost 1.54.0 and Ubuntu 12.04 (i386).
UPDATE 1: I made the test case a bit more realistic. The goal is to have a generic function that calls a functor under a lock and returns the value returned by the functor via boost::move() as the type of the return value might be movable but non-copyable (which is true in some of my invocations of call_under_lock()).
UPDATE 2: It turns out that a similar problem can be observed when using clang 3.5.1~(exp) in C++11 mode:
$ clang test.cpp -I../../boost_latest/ -lstdc++ --std=c++11
test.cpp:11:10: error: non-const lvalue reference to type 'basic_ostream<[2 * ...]>' cannot bind to a temporary of type 'basic_ostream<[2 * ...]>'
return boost::move(r);
^~~~~~~~~~~~~~
test.cpp:19:22: note: in instantiation of function template specialization 'call_under_lock<std::basic_ostream<char> &, boost::_bi::bind_t<std::basic_ostream<char> &, std::basic_ostream<char> &(*)(std::basic_ostream<char> &, int, int),
boost::_bi::list3<boost::reference_wrapper<std::basic_ostream<char> >, boost::_bi::value<int>, boost::_bi::value<int> > > >' requested here
std::ostream& os = call_under_lock<std::ostream&>(
UPDATE 3: This topic has also been discussed on boost-users mailing list [1].
[1] http://boost.2283326.n4.nabble.com/move-differences-between-results-in-C-03-and-C-11-modes-td4659264.html
What is the reason of such a failure?
In C++03, R is std::ostream&, and boost::move() evidently returns the same type, and so there is no problem.
In C++11, R is still std::ostream&, however boost::move() will return std::ostream&&. This makes the expression boost::move() an rvalue, which can not bind to a non-const lvalue reference.
Is there a way to workaround it in C++11 mode?
Yes:
template <class R, class F>
R call_under_lock(F f) {
// lock();
R r = f();
// unlock();
return r;
}
This should do exactly what you want in both C++03 and C++11. It will move when you want, and not move when you don't want.
I have tried to compile this (--std=c++0x) using:
[FAIL with --std=c++0x flag] clang version 3.2-1~exp9ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2)
[FAIL without --std=c++0x flag] clang version 3.2-1~exp9ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2)
[FAIL without --std=c++11 flag] Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM
3.3svn)
[FAIL with --std=c++11 flag] Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM
3.3svn)
[PASS with --std=c++0x flag] gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1)
[FAIL without --std=c++0x flag] gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1)
When it fails at clang ubuntu, the following errors are produced:
test.cpp:26:37: error: no viable conversion from 'const P' to 'timeval'
return static_cast<timeval>(_p);
^~
/usr/include/x86_64-linux-gnu/bits/time.h:30:8: note: candidate constructor
(the implicit copy constructor) not viable: no known conversion from 'const P' to
'const timeval &' for 1st argument
struct timeval
^
/usr/include/x86_64-linux-gnu/bits/time.h:30:8: note: candidate constructor
(the implicit move constructor) not viable: no known conversion from 'const P' to 'timeval &&' for
1st argument
struct timeval
^
test.cpp:9:5: note: candidate function
operator const timeval() const {
^
test.cpp:13:5: note: candidate function
operator const int8_t() const {
^
I am not sure what I am doing incorrectly.
#include <iostream>
#include <cstdint>
union P {
timeval _timeval;
int8_t _int8_t;
uint8_t _uint8_t;
operator const timeval() const {
return _timeval;
}
operator const int8_t() const {
return _int8_t;
}
};
struct Y {
operator const int8_t() const {
return static_cast<int8_t>(_p);
}
operator const timeval() const {
return static_cast<timeval>(_p);
}
P _p;
};
int main()
{
Y testobj;
timeval ret = static_cast<timeval>(testobj);
return 0;
}
As a starting point, you're missing the # from the beginnings of your #includes.
#include <iostream>
#include <cstdint>
You're also not including any header that should define the type timeval. Given the system(s) you're apparently using, you probably want:
#include <sys/time.h>
If you were using Windows, that would probably be:
#include <winsock2.h>
There are probably more problems, but that should at least get you started in the right general direction.
You may need to remove the first const from the conversion operators, because you are trying to cast the union to a non-const value later:
operator timeval() const {
return _timeval;
}
Abusing conversion operators seems like a bad idea. If you want encapsulation, consider creating proper methods like timeval getTimeval() const.