gcc fails to compile generic lambda with this capture [duplicate] - c++

This question already has an answer here:
Calling `this` member function from generic lambda - clang vs gcc
(1 answer)
Closed 6 years ago.
I cannot compile the following program with gcc 6.1:
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
class Foo
{
public:
void apply() const
{
std::for_each(std::cbegin(bars_), std::cend(bars_), [this] (const auto& x) { print(x); });
}
private:
std::vector<std::string> bars_;
void print(const std::string& x) const
{
std::cout << x << ' ';
}
};
int main()
{
Foo foo {};
foo.apply();
return 0;
}
The error message is:
error: cannot call member function 'void Foo::print(const string&) const' without object
std::for_each(std::cbegin(bars_), std::cend(bars_), [this] (const auto& x) { print(x); });
^~~~~
Changing const auto& x to const std::string& x makes the program compile.
Changing print(x) to this->print(x) makes the program compile.
All versions compile with Clang (Apple LLVM version 7.3.0 (clang-703.0.31)).
Is this a compiler bug?

This is a documented gcc bug which as of August 2016 has not been fixed yet.

I don't think the compiler is obliged to deduce the type being passed to the lambda inside the for_each function, bear in mind this function has already been compiled, how can the compiler know what the for_each function is going to pass to the lambda after it passed the lambda in?

I don't know why. But the solution is to specify which print it should use:
std::for_each(std::cbegin(bars_), std::cend(bars_), [this] (const auto& x) { this->print(x); });
With this it compiles.
See: http://coliru.stacked-crooked.com/a/1177b09a3e5863e2

Related

Why does some templated code fail to compile with MinGW-64 gcc version 11.2.0? [duplicate]

This question already has an answer here:
Can class template constructors have a redundant template parameter list in c++20
(1 answer)
Closed 1 year ago.
Specifically it is (an excerpt from https://github.com/dillonhuff/gpr), which fails to compile on line with parse_stream constructor definition:
#include "parser.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <streambuf>
using namespace std;
namespace gpr {
template<typename T>
struct parse_stream {
size_t i;
vector<T> s;
template<typename R>
parse_stream<T>(R v) : s(v.begin(), v.end()) { // COMPILE ERROR: expected ')' before 'v'
i = 0;
}
(...)
}
and parser.h just contains this:
#pragma once
#include <string>
#include "gcode_program.h"
namespace gpr {
std::vector<std::string> lex_block(const std::string& block_text);
gcode_program parse_gcode(const std::string& program_text);
gcode_program parse_gcode_saving_block_text(const std::string& program_text);
}
This used to compile just fine with MSVC 2019, and just "a while ago" with lower MinGW-64 gcc version. It seems to have something to do with C++ standard (17 vs 20), as lowering the C++ version settings in the Qt .pro file seems to fix it (but then I loose .contains() from std::map and couple of other features).
Maybe I am blind, but I just don't see, what is wrong here! Please help.
EDIT: Adding an exact compiler error
../gpr/src/parser.cpp:19:22: error: expected ')' before 'v'
19 | parse_stream<T>(R v) : s(v.begin(), v.end()) {
| ~ ^~
| )
EDIT: NathanOliver's comment helps to resolve the compilation. It compiles with (without the T parameter declaration):
template<typename R>
parse_stream(R v) : s(v.begin(), v.end()) { // NOW OK!
i = 0;
}
(Not sure if it is a fix or a workaround to a compiler bug, as the main question remains unanswered.)
Why is there no initializer for i in the list initializer?
It should read like this:
template <class R> explicit parse_stream(R v) : i{}, v{ std::vector<T>(v.begin(), v.end()) } {}
EDIT: It might make sense to provide an overload for the case where R is of decltype (v), namely a std::vector<T>, in which case we could just move the whole thing. Like this:
explicit parse_stream(std::vector<T> v) : i{}, v{ std::move(v) } {}

Lambdas, Is this keyword needed to disambiguate const/non-const member functions?

When I use MSVC to compile this program, I receive the error,
"Example::bar ambiguous call to overloaded function"
Then, I found that the this keyword was able to resolve the error. Surprised, I used rextester and found that both Clang and GCC were able to compile the program without the this keyword.
Here is the program in question.
#include <iostream>
class Example {
public:
Example() {
auto lambda = [this]() {
//this->bar<int>(); // Using this allows the program to compile and run successfully.
bar<int>(); // This doesn't work in MSVC
};
lambda();
}
template<typename T>
void bar() {
std::cout << "(non-const) bar\n";
}
template<typename t>
void bar() const {
std::cout << "(const) bar\n";
}
};
int main() {
Example example;
}
Ultimately I am asking, is this keyword needed in a lambda to disambiguate between const and non-const member functions and whether MSVC is correct or GCC and Clang are correct.
I am using Visual Studio 2017 and the full version of MSVC is 191627027

How to pass lambda to a lambda?

I have not managed to find why this code does not
work:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
auto xClosure = [](const function<void(int&)>& myFunction) {
myFunction(10);};
xClosure([]
(int& number) -> void
{cout<<number<<endl;
});
return 0;
}
It returns:
g++ test.cc -o test -std=c++14
test.cc:9:5: error: no matching function for call to object of type 'const function<void
(int &)>'
This has nothing to do with lambdas:
void test(const function<void(int&)>& myFunction) {
myFunction(10);
}
this fails to compile for the same reason; you cannot bind the literal 10 to an int&.
Maybe you meant
const function<void(int)>& myFunction
doing so and also modifying the signature of your lambda should make your code compile.

Problem replacing boost::bind with std::tr1::bind

I have the following code which compiles and runs fine under Visual Studio 2008 SP1.
#include <functional>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
class NoncopyableObject : public boost::noncopyable
{
public:
NoncopyableObject(int x) : x_(x) {}
int getValue() const {return x_;}
private:
int x_;
};
template<class F>
class MenuItemDispatcher
{
public:
MenuItemDispatcher(F f) : f_(f) { }
void operator ()(NoncopyableObject& w) const
{
// Invoke the functor
f_(w);
}
private:
typedef boost::function1<void,NoncopyableObject&> FUNC;
FUNC f_;
};
void MenuItem()
{
std::cout << "in MenuItem()\n";
}
template<class F>
MenuItemDispatcher<F> MakeMenuItemDispatcher(F f)
{
return MenuItemDispatcher<F>(f);
}
int main()
{
NoncopyableObject obj(7);
MakeMenuItemDispatcher(boost::bind(&MenuItem))(obj);
}
If I change the boost::bind to std::tr1::bind in main(), I get an error:
error C2248: 'boost::noncopyable_::noncopyable::noncopyable' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'.
This diagnostic occurred in the compiler generated function 'NoncopyableObject::NoncopyableObject(const NoncopyableObject &)'
So it's trying to generate a copy constructor for NoncopyableObject. Anyone know why this might be so please? MenuItemDispatcher's call operator takes a reference to a NoncopyableObject, so I am struggling to see what's going wrong.
This appears to be a difference in how bind is implemented in MS Visual Studio (including 2010) and GNU gcc (I tested 4.4.1 and 4.5.2, both of which work the way you expected)
Consider the following code, given your definitions
auto b = boost::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj); // OK in VS and GCC
replacing boost::bind with std::bind (I'm using 2010, the error message appears to be the same as in your 2008)
auto b = std::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj); // compile error in VS 2010 SP1, OK in GCC
b(std::reference_wrapper<NoncopyableObject>(obj)); // OK in both
So, what happens is that MS's bind() makes a copy of its argument even if the argument is not going to be used, while boost's and GCC's bind() does not bother with that argument at all.
I was able to get your example to compile and run (on 2010) by changing the FUNC typedef to
typedef boost::function1<void, std::tr1::reference_wrapper<NoncopyableObject> > FUNC;

g++ 4.1.2 compiler error

I have the following code (stripped down version from actual project to reproduce
the issue) that results in a compiler error on RHEL5 (g++ version 4.1.2):
----------- driver (test.cpp)--------------
#include <iostream>
#include <classa.hpp>
#include <func.hpp>
namespace globals {
static int kth(const A& a) {
return kth(a.ival());
}
}
using namespace globals;
int main() {
A a;
std::cout << func(a) << std::endl;
return 0;
}
----------class A (classa.hpp)------------
class A {
public:
A():val(0){}
const int ival() const {return val;}
private:
int val;
};
------- namespace globals (func.hpp) ------
namespace globals {
int kth(const int& c) {
return c;
}
template <class T>
int func(const T& key) {
return kth(key);
}
}
--------------------------------------------
Compiling it using g++ 4.1.2 gives me the following error:
func.hpp: In function ‘int globals::func(const T&) [with T = A]’:
test.cpp:15: instantiated from here
func.hpp:8: error: invalid initialization of reference of type ‘const int&’ from
expression of type ‘const A’
func.hpp:2: error: in passing argument 1 of ‘int globals::kth(const int&)’
Same code compiles and runs perfectly fine on RHEL4 (g++ version 3.4.6)! Any explanations/ideas/suggestions on how to resolve this error(?) on RHEL5 will
be much appreciated!
Edit:
Thanks Sergey. That is the obvious solution that I am aware of already. But I forgot to add that the restriction is that func.hpp cannot be edited (for e.g., its 3rd party write-protected). Any workarounds?
Here's what happens. When the function func() is defined, the compiler doesn't know about the function kth(const A&) yet because it is defined later in the code. So when it encounters a reference to kth() inside func(), it assumes that it is a reference to kth(const int&). Now when func() is actually instantiated, it fails to compile it because T is A, not int. I am not sure why it works in another version of the compiler, but I think it is because it actually starts resolving references when a template function is instantiated, not when it is declared. But this looks like a bug in the older version because with such behavior a function definition changes depending on where it is instantiated from, which is very confusing.
The only way to fix your code that it works with any compiler would be to put the definition of kth(const A&) between kth(const int&) and func() or a forward declaration of kth(const A&) somewhere above func().
Update
With the restriction of not editing func.hpp the best workaround I can think of is to create a custom header file with something like this:
#include <classa.hpp>
namespace globals {
static int kth(const A& a); // defined later, but used by func.hpp
}
#include <func.hpp>
I also don't see why kth(const A&) is defined as static, but used by a global header. I'd rather put it into the classa.cpp and its declaration into the classa.hpp. But this may be some design feature or artifact I am not aware of.