Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I think that the only technique which will work perfectly is to write a C wrapper function for each member function that you wish to invoke within a C callback; i.e.:</p> <pre><code>extern "C" void Foo_x(Foo *foo) { foo-&gt;x(); } extern "C" void Foo_x1(Foo *foo, int i) { foo-&gt;x1(i); } </code></pre> <p>You could also use lambda expressions of C++0x, which implicitly convert to a pointer to function having the same parameter and return types as the closure type’s function call operator. But, keep in mind that the language linkage of the function type is "C++", not "C".</p> <pre><code>#include &lt;cstdlib&gt; #include &lt;iostream&gt; using namespace std; struct Foo { void x() { cout &lt;&lt; "Foo::x()" &lt;&lt; endl; } void x1(int i) { cout &lt;&lt; "Foo::x1(" &lt;&lt; i &lt;&lt; ")" &lt;&lt; endl; } }; int main() { typedef void (*f_t)(Foo*); // default ("C++") language linkage typedef void (*f1_t)(Foo*, int); Foo foo; Foo_x(&amp;foo); Foo_x1(&amp;foo, -10); f_t fn = [] (Foo *foo) { foo-&gt;x(); }; fn(&amp;foo); f1_t fn1 = [] (Foo *foo, int i) { foo-&gt;x1(i); }; fn1(&amp;foo, 314); return EXIT_SUCCESS; } </code></pre> <p>Note that Section 5.2.2, Function call, of the C++ Standard states:</p> <blockquote> <p>Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function’s definition is undefined.</p> </blockquote> <p>So the following technically invokes undefined behavior:</p> <pre><code>extern "C" typedef void (*f_t)(Foo*); int main() { Foo foo; f_t fn = [] (Foo *foo) { foo-&gt;x(); }; fn(&amp;foo); // `fn` is a pointer to a function that uses "C++" language linkage, // but it is erroneously called through "C" language linkage. //... </code></pre> <p><strong>EDIT:</strong> After a bit of experimentation, I came up with the following template functions which return lambdas that call the given member function:</p> <pre><code>template &lt;typename return_t, class base, typename... arg_types&gt; std::function&lt;return_t (base*, arg_types...)&gt; make_lambda_to_call_member_function(return_t (base::*mem_fn)(arg_types...)) { return [mem_fn] (base *o, arg_types... args) -&gt; return_t { (o-&gt;*mem_fn)(args...); }; } template &lt;typename return_t, class base, typename... arg_types&gt; std::function&lt;return_t (const base*, arg_types...)&gt; make_lambda_to_call_member_function(return_t (base::*cmem_fn)(arg_types...) const) { return [cmem_fn] (const base *o, arg_types... args) -&gt; return_t { (o-&gt;*cmem_fn)(args...); }; } </code></pre> <p>If <code>Foo</code> is defined as:</p> <pre><code>struct Foo { void x() { cout &lt;&lt; "Foo::x()" &lt;&lt; endl; } void x1(int i) { cout &lt;&lt; "Foo::x1(" &lt;&lt; i &lt;&lt; ")" &lt;&lt; endl; } void cx1(float f) const { cout &lt;&lt; "Foo::cx1(" &lt;&lt; f &lt;&lt; ")" &lt;&lt; endl; } }; </code></pre> <p>Then you use the template <code>make_lambda_to_call_member_function</code> like:</p> <pre><code>auto fn = make_lambda_to_call_member_function(&amp;Foo::x); fn(&amp;foo); auto fn1 = make_lambda_to_call_member_function(&amp;Foo::x1); fn1(&amp;foo, 314); auto fn2 = make_lambda_to_call_member_function(&amp;Foo::cx1); fn2(&amp;foo, 44.832f); </code></pre> <p>Note, however, that the returned lambda objects will not implicitly convert to a function pointer because the lambda expression uses a lambda-capture.</p> <p>The latest draft of C++0x, n3225, states:</p> <blockquote> <p>The closure type for a <em>lambda-expression</em> with no <em>lambda-capture</em> has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type's function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type's function call operator.</p> </blockquote> <p>The following is illegal:</p> <pre><code>void (*fn5)(Foo*) = make_lambda_to_call_member_function(&amp;Foo::x); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload