2012-01-30 18 views
7

Próbuję utworzyć statycznie związaną klasę delegatów, w której funkcja elementu jest powiązana podczas kompilacji, co pomaga w optymalizacji.Odrzucenie argumentu szablonu dla wskaźnika do funkcji członka?

Mam następujący kod, który działa dokładnie tak, jak chcę go do:

#include <iostream> 

namespace thr { 

template<typename T, T func> 
struct delegate; 

template<typename R, 
     typename C, 
     typename... A, 
     R (C::* mem_fun)(A...)> 
struct delegate<R(C::*)(A...), mem_fun> 
{ 
    delegate(C* obj_) 
    : _obj(obj_) 
    {} 

    R operator()(A... a) 
    { 
    return (_obj->*mem_fun)(a...); 
    } 
private: 
    C* _obj; 
}; 

} // namespace thr 

struct foo 
{ 
    double bar(int i, int j) 
    { 
    return (double)i/(double)j; 
    } 
}; 

int main() 
{ 
    foo f; 

    typedef thr::delegate<decltype(&foo::bar), &foo::bar> cb;  
    cb c(&f); 

    std::cout << c(4, 3); 
    return 0; 
} 

Jednak użycie nie jest bardzo elegancki:

thr::delegate<decltype(&foo::bar), &foo::bar> 

Chciałbym użyć szablonu funkcji, która dedukuje parametry szablonu i zwraca instancję delegata; coś wzdłuż linii (ten kod nie skompilować):

template<typename C, typename T, T func> 
thr::delegate<T, func> bind(T func, C* obj) 
{ 
    return thr::delegate<decltype(func), func>(obj); 
} 

Pozwoliłoby to na bardziej elegancki składni:

auto cb = bind(&foo::bar, &f); 

Czy można wywnioskować parametr non-type w szablonie funkcji?

Czy to, co staram się osiągnąć w ogóle możliwe?

+0

Czasami można wydedukować parametr inny niż typ w szablonie funkcji, na przykład 'N' można wywnioskować w' szablonie size_t int_array_length (int (& array_ref) [N]) {return N;} '. Ale oczywiście 'N' jest częścią typu w sygnaturze funkcji, mimo że nie jest typem. –

+1

Dodaj makro: '#define MAKE_DELEGATE (x, y) thr :: delegate (y)' Nie widzę żadnego innego sposobu na uniknięcie dwukrotnego nazwania tej funkcji. –

+0

@Iori: Zdajesz sobie sprawę, że w twoim przykładzie 'T' będzie typem' func', więc 'decltype' nie jest konieczne :)? –

Odpowiedz

1

Możliwe jest wydedukować inne podmioty niż w rodzaju podpisu funkcji, ale funkcja Parametry sami nie mogą być następnie wykorzystane jako parametry szablonu.

Dane:

template <size_t I> struct Integral { static size_t const value = I; }; 

Możesz mieć:

template <size_t N> 
Integral<N> foo(char const (&)[N]); 

Ale nie można mieć:

Integral<N> bar(size_t N); 

W pierwszym przypadku, N jako rozmiar tablicy jest częścią rodzaju argumentu, w tym ostatnim przypadku, sam argument jest N. Można zauważyć, że w pierwszym przypadku N pojawiło się na liście parametrów szablonu podpisu typu.

W związku z tym, jeśli rzeczywiście jest to możliwe, wartość wskaźnika członka wartość musiałaby pojawić się jako część listy parametrów szablonu podpisu funkcji.

Nie może być zaletą korzystania constexpr, które można włączyć do regularnego wartość stałej dopasowanie do parametrów szablonu:

constexpr size_t fib(size_t N) { return N <= 1 ? 1 : fib(N-1) + fib(N-2); } 

Integral<fib(4)> works; 

Ale nie jestem na tyle bystry, aby pójść tą drogą ...

Mam jednak proste pytanie: dlaczego uważasz, że to przyspieszy sprawę? Kompilatory są bardzo dobre w stałej propagacji i wprowadzaniu, tak, że są w stanie wywoływać wywołania funkcji wirtualnych, gdy potrafią ocenić dynamiczny typ zmiennych podczas kompilacji. Jesteś pewien, że warto się nad tym pocić?

4

Czy std :: pomocy funkcji? http://www2.research.att.com/~bs/C++0xFAQ.html#std-function Twój przykład wygląda dość blisko.

myślę kompilator dostarczane STL robi całkiem strasznych rzeczy, aby to działało sprawnie. Przed podaniem możesz chcieć przyjrzeć się jako przykład.

Edit: I wyszedł i próbował co próbujesz osiągnąć. Mój wniosek jest błędem kompilacji:

  • Typ zwracanej powiązania (delegata) musi wskazywać wskaźnik na element, ponieważ jest to własne wymaganie.
  • bind powinien przyjąć nazwę wskaźnik do członka być elegancki (tzn swoje wymagania)
  • Kompilator wymaga nie cień parametr szablonu z parametrem funkcji lub użyć nazwy w obu parametrów i typu powrotu.

Dlatego jednym z wymagań musi odejść.

Edit 2: Pozwoliłem sobie zmieniających swoją delegata więc wiązać prace, jak chcesz. bind może nie być twoim priorytetem.

#include <iostream> 

namespace thr { 


template<typename C,typename R,typename... A> 
struct delegate 
{ 
private: 
    C* _obj; 
    R(C::*_f)(A...); 
    public: 
    delegate(C* obj_,R(C::*f)(A...)) 
    : _obj(obj_),_f(f) 
    {} 

    R operator()(A... a) 
    { 
    return (_obj->*_f)(a...); 
    } 

}; 

} // namespace thr 

template<class C,typename R,typename... A> thr::delegate<C,R,A...> bind(R(C::*f)(A...),C* obj){ 
    return thr::delegate<C,R,A...>(obj,f); 
} 

struct foo 
{ 
    double bar(int i, int j) 
    { 
    return (double)i/(double)j; 
    } 
}; 

int main() 
{ 
    foo f; 
    auto c = bind(&foo::bar, &f); 
    std::cout << c(4, 6); 
    return 0; 
} 
+0

'std :: function ' przyjmuje tylko typy w swoich parametrach szablonu i nie ma wartości. –

+0

Jak rozumiem, celem tego excersice nie jest jawne wpisanie typu delegata. Klapnięcie 'auto' powinno być możliwe i wystarczające. – artificialidiot

+0

Nie sądzę. Myślę, że celem było, aby funkcja wskaźnik-do-członka była parametrem szablonu (podobnie jak w przykładzie) i nie duplikowała informacji. –

Powiązane problemy