2012-07-31 18 views
14

Wiadomo, że argumenty szablonu mogą być wskaźnikami funkcji składowych.Odliczanie argumentów szablonu dla wskaźników funkcji członkowskich

Więc mogę napisać:

struct Bar 
{ 
    int fun(float x); 
}; 

template <int (Bar::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<&Bar::fun> FooBar; 

ale co jeśli chcę sam typ Bar być argumentem szablonu:

template <typename B, int (B::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<Bar, &Bar::fun> FooBar; 

Teraz, kiedy go używać, muszę napisać Bar dwa razy!

Moje pytanie brzmi: czy istnieje sposób zmuszenia kompilatora do automatycznego wyprowadzenia typu klasy?

Celem jest to, aby po prostu pracować:

typedef Foo<&Bar::fun> FooBar; 
typedef Foo<&Moo::fun> FooMoo; 

Odpowiedz

5

Prawdopodobnie powinieneś po prostu napisać tam nazwę klasy. Jeśli jednak naprawdę chcesz uniknąć, możesz użyć złej magii makr. Prosta wersja jest bardziej niebezpieczne:

#define TT(X) decltype(X), X 

template<typename T,T t> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

To będzie akceptować jakiejkolwiek non typu parametru szablonu, a może napotkać trudne do zrozumienia błędów jeśli realizacja Foo działa tylko z członka pointers do działania.

Żeby było nieco bezpieczniej trzeba metafunkcji że powie Ci nazwę klasy:

template<typename T> struct member_ptr_traits; 

template<typename Class,typename Ret,typename... Args> 
struct member_ptr_traits<Ret (Class::*)(Args...)> 
{ 
    typedef Class class_type; 
    typedef Ret return_type; 
}; 

#define TT(X) member_ptr_traits<decltype(X)>::class_type , X 

template<typename T,int (T::*FUN)(float)> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

też obu tych używać C++ 11, więc nie będą działać ze starymi kompilatorów. Ta prosta wersja może zostać przepisana, aby używać starego typeof lub podobnych rozszerzeń kompilatora. Przepisanie bezpieczniejszej wersji wymaga symulowania szablonów variadic.

+0

Właściwie używam do tego nieprzyjemnych makr (jest to szablon wewnętrzny biblioteki, więc nie istnieje realne ryzyko niewłaściwego użycia). W każdym razie 'member_ptr_traits' jest świetne, ponieważ faktycznie potrzebuję typu' T'. – rodrigo

7

Prosta odpowiedź: nie ma.

Problem polega na tym, że aby szablon mógł działać, szablon musiałby mieć pojedynczy argument nie typu, ale typ tego argumentu byłby nieznany podczas deklarowania szablonu, co nie jest poprawne. Z drugiej strony, dedukcja typu nigdy nie jest stosowana do argumentów szablonu (tylko do argumentów dla szablonów funkcji, ale są to argumenty funkcji, a nie szablonu).

+0

Zrozumiano. Więc nie byłoby to możliwe także dla funkcji szablonu, prawda? – rodrigo

+0

@rodrigo: Jeśli chcesz wziąć ten argument szablonu jako wskaźnik do członka tak. Pytanie brzmi, czy potrzebujesz wskaźnika do elementu będącego argumentem szablonu, czy może to być argument funkcji, który można wyprowadzić. –

+0

Tak, potrzebuję go jako argumentu szablonu, ponieważ musi być użyty do utworzenia instancji zagnieżdżonego szablonu. W każdym razie, dziękuję za twój wgląd – rodrigo

Powiązane problemy