Lambda functions as base classes
In addition to operator()
, a the class defined by a lambda can (under the right circumstances) provide a conversion to a pointer to function. The circumstance (or at least the primary one) is that the lambda can't capture anything.
If you add a capture:
auto f1 = get(
[]() { std::cout << "lambda1::operator()()\n"; },
[i](int) { std::cout << "lambda2::operator()(int)\n"; }
);
f1();
f1(2);
...the conversion to pointer to function
is no longer provided, so trying to compile the code above gives the error you probably expected all along:
trash9.cpp: In function 'int main(int, char**)':
trash9.cpp:49:9: error: no match for call to '(Overload<main(int, char**)::<lambda()>, main(int, char**)::<lambda(int)> >) (int)'
trash9.cpp:14:8: note: candidate is:
trash9.cpp:45:23: note: main(int, char**)::<lambda()>
trash9.cpp:45:23: note: candidate expects 0 arguments, 1 provided
Lambda expressions with properties from base class
For me it works fine:
See this example here, probably there is something else causing the issue:
public void Main()
{
List<PlayerData> playerdata = new List<PlayerData>
{
new PlayerData
{
isSelected = true,
distance = 3,
nickname = "First",
},
new PlayerData
{
isSelected = true,
distance = 3,
nickname = "Second",
},
new PlayerData
{
isSelected = true,
distance = 3,
nickname = "Third",
}
};
PlayerData player = playerdata.Find(x => x.isSelected);
Console.WriteLine(player);
}
public class BaseData
{
public bool isSelected;
public int distance;
}
public class PlayerData: BaseData
{
public string nickname;
public override string ToString() { return this.nickname;}
}
The result is 'First' as expected since it is the first player in the list.
How capture derivated this in base class into lambda function?
While a thread is started, no attempt to join it is made, so the process happily terminate after calling d.foo();
in main
.
If you give a getter to the thread, in class Base
std::thread * theThread() { return t; }
in your main
:
int main() {
Derivated d;
d.foo();
d.theThread()->join();
}
This way the main thread gets blocked and the other thread is free to go on (and on).
Lambda expressions and anonymous classes don't work when loaded as hidden classes
You can not turn arbitrary classes into hidden classes.
The documentation of defineHiddenClass
contains the sentence
- On any attempt to resolve the entry in the run-time constant pool indicated by
this_class
, the symbolic reference is considered to be resolved toC
and resolution always succeeds immediately.
What it doesn’t spell out explicitly is that this is the only place where a type resolution ever ends up at the hidden class.
But it has been said unambiguously in bug report JDK-8222730:
For a hidden class, its specified hidden name should only be accessible through the hidden class's 'this_class' constant pool entry.
The class should not be accessible by specifying its original name in, for example, a method or field signature even within the hidden class.
Which we can check. Even a simple case like
public class HiddenClassLambdaTest {
public static void main(String[] args) throws Throwable {
byte[] classFileContents = HiddenClassLambdaTest.class
.getResourceAsStream("HiddenClassLambdaTest$LambdaRunner.class")
.readAllBytes();
var hidden = MethodHandles.lookup()
.defineHiddenClass(classFileContents, true, ClassOption.NESTMATE);
Runnable lambdaRunnerInstance = (Runnable)hidden.findConstructor(
hidden.lookupClass(), MethodType.methodType(void.class)).invoke();
lambdaRunnerInstance.run();
}
static class LambdaRunner implements Runnable {
LambdaRunner field = this;
@Override
public void run() {
}
}
}
will already fail. Note that it is a special case that the attempt to resolve the original class name LambdaRunner
within the hidden class will not fail, as you used an existing class as template. So you get an IncompatibleClassChangeError
or a VerifierError
due to mismatches between the hidden class and the existing LambdaRunner
class. When you don’t use a class definition of an existing class, you’d get a NoClassDefFoundError
.
The same applies to
static class LambdaRunner implements Runnable {
static void method(LambdaRunner arg) {
}
@Override
public void run() {
method(this);
}
}
As the cited bug report said, neither field nor methods can refer to the hidden class in their signature.
A less intuitive example is
static class LambdaRunner implements Runnable {
@Override
public void run() {
System.out.println("" + this);
}
}
which will fail depending on the compiler and options, as when the StringConcatFactory
is used, the behavior is like an invocation of a method having all non-constant parts as parameters and returning a String
. So this is another case of having the hidden class in a method signature.
Lambda expressions are special, as a class like
static class LambdaRunner implements Runnable {
@Override
public void run() {
Runnable runnable = () -> System.out.println("Success");
runnable.run();
}
}
gets compiled similar to
static class LambdaRunner implements Runnable {
@Override
public void run() {
Runnable runnable = LambdaRunner::lambdaBody;
runnable.run();
}
private static void lambdaBody() {
System.out.println("Success");
}
}
which doesn’t have the hidden class in the method signature, but has to refer to the method holding the body of the lambda expression as a MethodReference
. Within the constant pool, the description of this method refers to its declaring class using the this_class
entry. So it gets redirected to the hidden class as described in the documentation.
But the construction of the MethodType
as part of the MethodReference
does not use this information to load a Class
like a class literal would do. Instead, it tries to load the hidden class through the defining class loader, which fails with the NoClassDefFoundError
you have posted.
This seems to be related to JDK-8130087 which suggests that ordinary method resolution differs from the way, MethodType
works, which can make MethodType
fail where just invoking the method would work.
But it’s possible to demonstrate that even fixing this issue wouldn’t solve the general problem:
static class LambdaRunner implements Runnable {
@Override
public void run() {
var lookup = MethodHandles.lookup();
var noArgVoid = MethodType.methodType(void.class);
try {
MethodHandle mh = LambdaMetafactory.metafactory(lookup, "run",
MethodType.methodType(Runnable.class), noArgVoid,
lookup.findStatic(LambdaRunner.class, "lambdaBody", noArgVoid),
noArgVoid).getTarget();
System.out.println("got factory");
Runnable runnable = (Runnable)mh.invokeExact();
System.out.println("got runnable");
runnable.run();
}
catch(RuntimeException|Error e) {
throw e;
}
catch(Throwable e) {
throw new AssertionError(e);
}
}
private static void lambdaBody() {
System.out.println("Success");
}
}
This bypasses the problem described above and calls the LambdaMetafactory
manually. When being redefined as hidden class, it will print:
got factory
got runnable
Exception in thread "main" java.lang.NoClassDefFoundError: test/HiddenClassLambdaTest$LambdaRunner/0x0000000800c01400
at test/test.HiddenClassLambdaTest.main(HiddenClassLambdaTest.java:15)
Caused by: java.lang.ClassNotFoundException: test.HiddenClassLambdaTest$LambdaRunner.0x0000000800c01400
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 1 more
which shows that all obstacles have been circumvented, but when it comes to the actual invocation from the generated Runnable
to the method holding the lambda body, it will fail due to the fact that the target class is hidden. A JVM with eager resolution of symbolic references might fail earlier, i.e. the example might not print got runnable
then.
Unlike the old JVM anonymous classes, there is no way to link to a hidden class, not even from another hidden class.
The bottom line is, as said at the beginning, you can not turn arbitrary classes into hidden classes. Lambda expressions are not the only feature not working with hidden classes. It’s not a good idea to try and get surprised. Hidden classes should only be used in conjunction with bytecode generators carefully using only features known to work.
Inherited parameter in lambda function in C++
How about, instead of SomeClass
being a regular class, making it a the base class of a class template that handles having the proper functor type, as well as downcasting to the right type ?
It would look like this:
class SomeClass
{
virtual void callFunc(Base*) = 0;
}
template<typename T>
class SomeDerivedClass : public SomeClass
{
static_assert(std::is_base_of<Base, T>::value, "SomeDerivedClass: unexpected base class");
virtual void callFunc(Base* b) override
{
execFunc(static_cast<T*>(b));
}
void (*execFunc)(T*);
}
Base
then becomes:
class Base
{
SomeClass* someClass;
void doSomething() { someClass->callFunc(this); }
}
Then, in your Derived
definition:
class Derived final : public Base
{
int someDerivedAttrib;
typedef SomeDerivedClass<Derived> tSomeClass;
static List<tSomeClass*> someClasses = createSomeClasses(); // holds all possible
// SomeClasses for this
// derived class
static List<tSomeClass*> createSomeClasses()
{
List<tSomeClass*> scs;
tSomeClass* sc = new tSomeClass();
sc->execFunc = [] (Derived* derived) { derived->someDerivedAttrib = 10; };
scs << sc;
return scs
}
}
However, this runs the risk of calling SomeDerivedClass::call
with the wrong concrete class.
Using lambda expression from a child class
You can build your Expression on you own. Just add another parameter to GetExpression
:
public static Expression<Func<MyCustomClass, bool>> GetExpression(
string derrivedName, // "Product" or "Country"
int fieldId,
string value)
{
var x = Expression.Parameter(typeof(MyCustomClass), "x");
var lambda = Expression.Lambda<Func<MyCustomClass, bool>>(
Expression.Equal(
Expression.Constant(value),
Expression.PropertyOrField(
Expression.PropertyOrField(x, derrivedName),
$"Field{fieldId}")
),
x);
return lambda;
}
Now you can use it like:
var exp3 = GetExpression("Product", 1, "Fruit");
This line will create an expression x => ("Fruit" == x.Product.Field1)
Lambda Expressions for Abstract Classes
You cannot directly make a lambda expression target an abstract class, as Sleiman Jneidi pointed out in his answer. However, you can use a workaround:
public class AbstractLambda<T> extends Abstract<T>
{
private final Supplier<? extends T> supplier;
public AbstractLambda(Supplier<? extends T> supplier)
{
this.supplier = supplier;
}
@Override
public T getSomething()
{
return this.supplier.get();
}
}
This can be used with a lambda expression:
Abstract<String> a = new AbstractLambda<>(() -> "Hello World");
System.out.println(a.getSomething()); // prints 'Hello World'
In case your getSomething(...)
method has arguments, use a java.util.function.Function
or the appropriate interface from the java.util.function
package instead of java.util.function.Supplier
.
This is also how the java.lang.Thread
lets you use a Runnable
lambda instead of having to subclass the class:
Thread t = new Thread(() -> System.out.println("Hello World"));
t.start();
c++ lambda function calls pure virtual function
Just a guess based on what I've tried: your Consumer
gets destructed before the thread executes.
I've made ~Executor
virtual and added some print statements for relevant function calls.
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
class Executor
{
public:
// constructor
Executor();
// destructor
virtual ~Executor();
// kick thread execution
void Kick();
private:
// thread execution function
virtual void StartExecution() { std::cout << "Executor::Kick\n"; }
// thread handle
std::thread mThreadHandle;
};
Executor::Executor()
{
// Nothing to be done here
}
Executor::~Executor()
{
std::cout << "~Executor\n";
if (mThreadHandle.joinable())
mThreadHandle.join();
}
void Executor::Kick()
{
// mThreadHandle = std::thread(&Executor::StartExecution, this);
mThreadHandle = std::thread([this] {this->StartExecution();});
}
class Consumer: public Executor {
public:
~Consumer() {
std::cout << "~Consumer\n";
}
private:
virtual void StartExecution() { std::cout << "Consumer::Kick\n"; }
};
int main() {
{
std::cout << "1:\n";
std::unique_ptr<Consumer> consumer = std::make_unique<Consumer>();
consumer->Kick();
}
{
std::cout << "2:\n";
std::unique_ptr<Consumer> consumer = std::make_unique<Consumer>();
consumer->Kick();
std::cout << "Sleeping for a bit\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
Output:
1:
~Consumer
~Executor
Executor::Kick
2:
Sleeping for a bit
Consumer::Kick
~Consumer
~Executor
See it run here
Sleeping before destroying the consumer lets the thread run and call the correct function. A "real" solution would be to ensure that the consumer lives at least as long as the thread itself. Since the thread exists in the base class Executor
this isn't guaranteed, as derived classes are destructed before base classes.
From cppreference (emphasis mine):
When a virtual function is called directly or indirectly from a constructor or from a destructor (including during the construction or destruction of the class’s non-static data members, e.g. in a member initializer list), and the object to which the call applies is the object under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. In other words, during construction or destruction, the more-derived classes do not exist.
This appears to apply when a member function is called in a different thread during construction/destruction.
Related Topics
Restrict Variadic Template Arguments
Add External Libraries to Cmakelist.Txt C++
How Do Memory_Order_Seq_Cst and Memory_Order_Acq_Rel Differ
Convert Eigen Matrix to C Array
Simpler Way to Create a C++ Memorystream from (Char*, Size_T), Without Copying the Data
C++: How to Get Fprintf Results as a Std::String W/O Sprintf
C++Cli. Are Native Parts Written in Pure C++ But Compiled in Cli as Fast as Pure Native C++
Stl Containers with Reference to Objects
When to Use Functors Over Lambdas
Changing Dpi Scaling Size of Display Make Qt Application's Font Size Get Rendered Bigger
Does an R Compiler to C/C++ Exist
Performance Wise, How Fast Are Bitwise Operators VS. Normal Modulus
Is Writing to &Str[0] Buffer (Of a Std:String) Well-Defined Behaviour in C++11
How to Access Variables Defined and Declared in One Function in Another Function