Thread overview | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
October 25, 2014 function pointer bug? | ||||
---|---|---|---|---|
| ||||
I am trying to store a function pointer in a class in a generic way(works with all member/non-member/global functions). In the main() function below, there are two cases(A, B). If case B is commented out, this code complies/runs fine. Otherwise, I get these errors, and the compiler pointing at "dg.funcptr = &T[0];" in TestClas.invoke(void*). Error: this for instanceMethod needs to be type TestClass not type main.FuncPtr!(instanceMethod).FuncPtr Error: cannot implicitly convert expression (&(__error).instanceMethod) of type void delegate() to void function() Error: template instance main.FuncPtr!(instanceMethod) error instantiating Am I missing something here or is this a bug? class TestClass { void instanceMethod() { writeln("Instance Method!"); } static void staticMethod() { writeln("Static Method!"); } } void GlobalMethod() { writeln("Global Method!"); } void invokeFunction(T...)(void *instance){ alias typeof(T[0]) method_type; alias ReturnType!method_type return_type; alias ParameterTypeTuple!method_type param_types; alias return_type delegate(param_types) delegate_type; delegate_type dg; dg.ptr = instance; dg.funcptr = &T[0]; dg(); } class FuncPtr(T...) { void invoke(void *instance) { alias typeof(T[0]) method_type; alias ReturnType!method_type return_type; alias ParameterTypeTuple!method_type param_types; alias return_type delegate(param_types) delegate_type; delegate_type dg; dg.ptr = instance; dg.funcptr = &T[0]; dg(); } } void main() { TestClass testClass = new TestClass(); // case A invokeFunction!(TestClass.instanceMethod)(cast(void*)testClass); invokeFunction!(TestClass.staticMethod)(null); invokeFunction!(GlobalMethod)(null); // case B auto fp1 = new FuncPtr!(TestClass.instanceMethod); auto fp2 = new FuncPtr!(TestClass.staticMethod); auto fp3 = new FuncPtr!(GlobalMethod); fp1.invoke(cast(void*)testClass); fp2.invoke(null); fp3.invoke(null); } |
October 27, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | Looks like &T[0] tries to take delegate to instanceMethod, hence complains about this type. |
October 27, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | It works after I added 'static' to the declaration of 'invoke()' (and import std.stdio, std.traits.) I fiddled around with it for hours before I tried 'static' there, because I've only been studying D for a week, so only about half of this code and the error messages made any sense to me when I started on it. Once it started passing all the tests, I still didn't quite get how it all worked, because of suspecting there was a typo in the code between writing TestClass and testClass. So I tested whether specific instances are called (instead of maybe just the first one constructed) by adding a static counter to TestClass, and storage of the counter by each instance. It looks all right. |
October 27, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Solomon E | On Monday, 27 October 2014 at 16:08:26 UTC, Solomon E wrote: > It works after I added 'static' to the declaration of 'invoke()' (and import std.stdio, std.traits.) > > I fiddled around with it for hours before I tried 'static' there, because I've only been studying D for a week, so only about half of this code and the error messages made any sense to me when I started on it. > > Once it started passing all the tests, I still didn't quite get how it all worked, because of suspecting there was a typo in the code between writing TestClass and testClass. So I tested whether specific instances are called (instead of maybe just the first one constructed) by adding a static counter to TestClass, and storage of the counter by each instance. It looks all right. I'm pretty sure this is a bug. I'm going to file a report. If one of those template works, both should. I have been trying to build a reflection system over the last few weeks, and noticed different incarnations of this problem several times: <b> &(__error).instanceMethod </b> In certain cases, the compiler seems to drop the enclosing type of the method, but I'm not sure why. This error seems like it may be related some how: enum index = __traits(getVirtualIndex, TestClass.instanceMethod); enum p = TestClass.classinfo.vtbl[index]; The above code will produce this error: Error: typeid(main.TestClass).vtbl is not yet implemented at compile time but if this is the problem, shouldn't Both of the test cases fail? |
October 27, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise Attachments: | On Mon, 27 Oct 2014 22:17:24 +0000 bitwise via Digitalmars-d <digitalmars-d@puremagic.com> wrote: > I have been trying to build a reflection system over the last few weeks, and noticed different incarnations of this problem several times: > > &(__error).instanceMethod this means that something gone wrong in the process. '(__error)' is the "pseudotype" for failed CTFE/instantiation. > This error seems like it may be related some how: > > enum index = __traits(getVirtualIndex, TestClass.instanceMethod); enum p = TestClass.classinfo.vtbl[index]; > > The above code will produce this error: > Error: typeid(main.TestClass).vtbl is not yet implemented at > compile time > > but if this is the problem, shouldn't Both of the test cases fail? why? everything is ok here. you can get method index in compile-time, but there is no built VMT in compile time. what do you want to achieve with second enum? |
October 27, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | > this means that something gone wrong in the process. '(__error)' is the > "pseudotype" for failed CTFE/instantiation. But why did the instantiation fail? and more importantly, why did it not have consistent behaviour between the two templates above? >what do you want to achieve >with second enum? I'm just trying to come up with a test case which may offer some insight into what's going wrong with the code in the OP. for example, I am wondering how far this issue extends; meaning, is it only classinfo.vtbl that's not available at compile time? or is it the address of member functions as a whole that are unavailable? The code below suggests the latter, although it doesn't explicitly state it: static addr = &TestClass.instanceMethod; Error: non-constant expression & instanceMethod I may be missing a subtle difference, but in C++, this code works: class TestAddr { public: virtual void test() { cout << "test" << endl; } }; int main(int argc, const char * argv[]) { TestAddr test; static auto ptr = &TestAddr::test; (test.*ptr)(); return 0; } so why would it not in D? |
October 27, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | >> quotes self
Here is a better example, showing that virtual function pointers are available at compile time in C++. Essentially, I would expect my D code to function similarly, but it won't compile.
class TestAddr {
public: virtual void test() { cout << "test" << endl; }
};
template<void (TestAddr::*FN)()>
class PtrWrapper
{
public:
void invoke(TestAddr *instance) { (instance->*FN)(); }
};
int main(int argc, const char * argv[])
{
TestAddr test;
PtrWrapper<&TestAddr::test> wrapper;
wrapper.invoke(&test);
return 0;
}
|
October 28, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise Attachments: | On Mon, 27 Oct 2014 23:52:38 +0000 bitwise via Digitalmars-d <digitalmars-d@puremagic.com> wrote: > The code below suggests the latter, although it doesn't explicitly state it: > > static addr = &TestClass.instanceMethod; > Error: non-constant expression & instanceMethod > > I may be missing a subtle difference, but in C++, this code works: > > class TestAddr { > public: virtual void test() { cout << "test" << endl; } > }; > > int main(int argc, const char * argv[]) > { > TestAddr test; > static auto ptr = &TestAddr::test; > (test.*ptr)(); > return 0; > } C++ compiler does some trickery behind the curtains. besides, you aren't supposed to make such hackish things easily in D. yet you can: class TestClass { int n = 42; void test() { writeln("test: ", n); } } void main () { auto test = new TestClass(); void delegate () a; { a.ptr = *cast(void**)&test; // protection from opCast() // this can be done as `cast(void*)test;` too enum idx = __traits(getVirtualIndex, TestClass.test); a.funcptr = cast(void function())TestClass.classinfo.vtbl[idx]; a(); // outputs 'test: 42' } } you need to manually create initialization code that C++ compilers creates behind the curtains. if you aren't in urgent need of that code, may i suggest you to read D books and D specs? D is not C++, and D delegates aren't C++ member function pointers (yet they works nearly the same). this is kind of advanced topic, and i don't think that dumping working source code at you will help without you grasp the low-level mechanics first. besides, you can use CTFE to build wrapper code. Adam Ruppe has that in his jsvar.d, and i have that in my cong.d (cmdcon-ng) too. not that i'm not willing to help you, but i can't see what you understand and what not, so i don't know where i should start explaining. |
October 28, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | > C++ compiler does some trickery behind the curtains. besides, you > aren't supposed to make such hackish things easily in D. yet you can: There is nothing hackish in the above code. It's a non-type template parameter and a member function pointer. If I was trying to access the (implementation dependant)vtable pointer in C++ to call the function manually, I may concede to calling it a hack, but there is nothing non-standard about the above code. >>D is not C++, and D delegates aren't C++ member function pointers (yet they works nearly the same). I was simply trying to show that what I wanted to do was possible in a similar language. I still believe it's a bug in the language. In the original code, both test cases should either both work, or both fail to compile. I have looked through the D docs online, and can't find anything supporting the argument that this is the intended behaviour of the compiler. |
October 28, 2014 Re: function pointer bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | >> besides, you can use CTFE to build wrapper code. Adam Ruppe has that in >> his jsvar.d, and i have that in my cong.d (cmdcon-ng) too. I have actually found a work around as well, which was to wrap the actual retrieval of the function address in a lambda, and pass the lambda by template parameter instead: auto getMethod = function() { return &__traits(getMember, SCOPE, member); }; this is later assigned to a delegate when called: delegate_type dg; dg.ptr = instance; dg.funcptr = getMethod(); dg(); The above works for global or static functions too. This seems to me like an unnecessary workaround though.. my current project can be viewed here: https://github.com/bitwise-github/D-Reflection/blob/master/reflection.d#L796 It's been implemented based on Andrei's suggestions here: http://forum.dlang.org/thread/juf7sk$16rl$1@digitalmars.com as far as I could google, no one has attempted this yet. My prototype works pretty much as he has described, less a feature here and there. |
Copyright © 1999-2021 by the D Language Foundation