2014-12-17 18 views
6

bir dizi isteyen bir C işlevi: Bir EXTENSIONFUNCTION ve kayıtbir std proxy aracılığıyla :: işlevini Bu formun bir kanca sunan bir C sistemiyle uğraşıyorum argümanları

int (*EXTENSIONFUNCTION)(NATIVEVALUE args[]); 

Mümkün aldığı argüman sayısı.

Fikrim, bir uzantıyı sarmak için bir sınıf Extension yapmam oldu. Bir std :: function 'dan (ya da herhangi bir Callable, ideal olarak, ancak bunun için şimdi bir std :: işlevi içerdiğini varsayalım). Ve uzantı, NATIVEVALUE (ancak daha büyük)'u kapatan Değer parametrelerini alır. Örneğin, parametre sayısını sizeof...(Ts) ile otomatik olarak halledebilirim. Bu gibi görünebilir:

Extension<lib::Integer, lib::String> foo = 
    [](lib::Integer i, lib::String s) -> int { 
     std::cout << i; 
     std::cout << s; 
     return 0; 
    } 

Sorun kaydetmek ve çağırmak için C kütüphanesi için sırayla, o dizi tabanlı arayüz istemesi. : -/

Derleyicinin biraz shim yazmasını denemek için yola çıktım, ancak bunu yapmanın bir yolunu göremiyorum. Extension'da variadic operator() olabilir ve bir değer [] değeri almak için NATIVEVALUE üzerinde bir çalışma zamanı döngüsü yapın. Ama ben bununla ne yapıyorum? Std :: işlevini onunla arayamıyorum.

Yani her Extension örneğinin bir üyesi olarak std :: işlevimi çağıran EXTENSIONFUNCTION örneği yapmam gerekiyor.

Ama temel olarak kendimi, bir uzantı için değişken bir templated sınıfına sahip olduğum bir duvara karşı buluyorum ... ve sonra bu NATIVEVALUE args[]'u ele alarak, "buradan oraya gidemiyorum". std :: işlevini onlarla arayın. Std :: işlevi bir std :: argüman dizisi ile çağrılmaya istekli olsaydı, bu onu çözerdi, ama tabii ki böyle değil.

Bu tip bir çerçeve oluşturmak mümkün mü? Yapabileceğim "çirkin" bir şey gibi başka bir diziye sadece proxy'dir:

Extension<2> foo = 
    [](lib::Value args[]) -> int { 
     lib::Integer i (args[0]); 
     lib::String s (args[1]); 
     std::cout << i; 
     std::cout << s; 
     return 0; 
    } 

Ama bu ergonomik olarak değil. Arama kuralı bilmeden ve parametrelerini işlemek için bir dizi satır içi montaj malzemesi yapmadan ve işlevini ÇAĞRIYOR (ve hatta bu işlevler için genel olarak Callables değil) çalışır.. Ama burada insanlar genellikle yoluyla, daha önce imkansız mümkün kanıtlanmıştır "diye sen aslında ne istediğini, istediğin bu değil ..."


GÜNCELLEME: Sadece hangi görünüyor buldum umut verici ... Ben hala onun alaka sindirmek için çalışıyorum:

"unpacking" a tuple to call a matching function pointer

(Not: Ben amaçladığımız şey birkaç kesişen konu vardır başka nokta lambdas çıkarımlar türüdür.. Cevap en iyisi gibi görünüyor o iş gibi görünüyor ... o bahis, ancak "koşer" ise bilmiyorum: Initialize class containing a std::function with a lambda)

+0

'EXTENSIONFUNCTION' işlevi 'Extension' sınıfını çağırabilmek için bir 'void * userData 'almıyor gibi görünüyor, sorununuzu nasıl çözeceğinizi bilmiyorum. – Jarod42

+0

'NATIVEVALUE' nedir? Belki dizinin ilk elemanında 'Extension' işaretçisini gösterebilirsiniz. –

+0

Burada koyduğunuz şeyi okumakta biraz zor bir zaman geçirdim, ama * düşünüyorum * belki de onun gibi [http://ideone.com/fJlkK6]. Eğer değilse, umarım en azından size bazı fikirler verir. İyi şanslar. – WhozCraig

cevap

2

Ben sade forma sorunu azaltmak başardı varsa, bir std::function aramak için bir yol gerekir argümanını, bir çalışma zamanı döngüsü oluşturmaya gerek kalmadan sabit boyutlu bir C stili diziden almak.İşte

template<std::size_t N, typename T, typename F, std::size_t... Indices> 
auto apply_from_array_impl(F&& func, T (&arr)[N], std::index_sequence<Indices...>) 
    -> decltype(std::forward<F>(func)(arr[Indices]...)) 
{ 
    return std::forward<F>(func)(arr[Indices]...); 
} 

template<std::size_t N, typename T, typename F, 
     typename Indices = std::make_index_sequence<N>> 
auto apply_from_array(F&& func, T (&arr)[N]) 
    -> decltype(apply_from_array_impl(std::forward<F>(func), arr, Indices())) 
{ 
    return apply_from_array_impl(std::forward<F>(func), arr, Indices()); 
} 

bir örnek bunun nasıl kullanılabileceğini sergiliyor: Sonra, bu işlevler sorununuzu çözebilir Tabii

auto foo = [](int a, int b, int c) 
    -> int 
{ 
    return a + b + c; 
}; 

int main() 
{ 
    Value arr[] = { 1, 2, 3 }; 

    std::cout << apply_from_array(foo, arr); // prints 6 
} 

imza int (*)(T args[]) ile args sadece T* ve don olduğu Derleme zamanında boyutunu bilir. Böyle işlevi

template<std::size_t N, typename T, typename F, std::size_t... Indices> 
auto apply_from_array_impl(F&& func, T* arr, std::index_sequence<Indices...>) 
    -> decltype(std::forward<F>(func)(arr[Indices]...)) 
{ 
    return std::forward<F>(func)(arr[Indices]...); 
} 

template<std::size_t N, typename T, typename F, 
     typename Indices = std::make_index_sequence<N>> 
auto apply_from_array(F&& func, T* arr) 
    -> decltype(apply_from_array_impl<N>(std::forward<F>(func), arr, Indices())) 
{ 
    return apply_from_array_impl<N>(std::forward<F>(func), arr, Indices()); 
} 

Ve sonra kullanın: Başka bir yere ait (örneğin std::function itibaren) dan derleme zamanı boyutunu bilmek Ancak, yine de el derleme zamanı boyutu bilgi vermek apply_from_array ince ayar yapabilirsiniz: yukarıdaki örnekte

int c_function(NATIVEVALUE args[]) 
{ 
    return apply_from_array<arity>(f, args); 
} 

, f bir std::function olduğunu düşünün ve arity o derleme zamanında, öyle ya da böyle başardı f arasında Arity olduğunu.

NOT: C++ 14 std::index_sequence ve std::make_index_sequence ancak C++ 11 ile çalışacak şekilde kodu gerekir, yine de benim eski Söz konusu indices ve make_indices gibi el işi eşdeğerleri kullanabilir kullanılan sen bağlandın


Sonrası: soru yaklaşık real code, elbette yukarıda daha biraz daha karmaşıktı ediliyor. Uzantı mekanizması, her uzatma fonksiyonu çağrıldığında, C API (lib::Integer, lib::String, vb.) Üzerindeki C++ proksisi uçta oluşturulur, ardından kullanıcı tanımlı işleve iletilir. altında yatan C API

template<typename Func, std::size_t... Indices> 
static auto applyFuncImpl(Func && func, 
          Engine & engine, 
          REBVAL * ds, 
          utility::indices<Indices...>) 
    -> decltype(auto) 
{ 
    return std::forward<Func>(func)(
     std::decay_t<typename utility::type_at<Indices, Ts...>::type>{ 
      engine, 
      *D_ARG(Indices + 1) 
     }... 
    ); 
} 

template < 
    typename Func, 
    typename Indices = utility::make_indices<sizeof...(Ts)> 
> 
static auto applyFunc(Func && func, Engine & engine, REBVAL * ds) 
    -> decltype(auto) 
{ 
    return applyFuncImpl(
     std::forward<Func>(func), 
     engine, 
     ds, 
     Indices {} 
    ); 
} 

applyFunc (... vb Integer, String) uygun tipte örnek bulunmayan bir çağrı yapılmasına adlandırmak işlevini alır anında: Bu yeni bir yöntem, applyFuncExtension gerekli Engine& ve REBVAL* ile anında oluşturuldu.

+0

Tüm yardımlarınız için tekrar teşekkürler ... görev çağrısı yukarıda ve ötesinde ...! – HostileFork