2010-01-24 21 views
5

Zastanawiam się, czy możliwe jest rozszerzenie podejścia SFINAE na wykrywanie, czy dana klasa ma pewną funkcję członka (jak omówiono tutaj:Jak ustalić, czy dana klasa ma określoną funkcję na szablonie?

"Czy istnieje technika w C++, aby wiedzieć, czy klasa ma funkcję członka z podpisem? " Check if a class has a member function of a given signature

) w celu obsługi szablonowych funkcji składowych? Na przykład. aby być w stanie wykryć funkcji foo w poniższej klasy:

struct some_class { 
    template < int _n > void foo() { } 
}; 

I że może to być możliwe, aby to zrobić dla danej instancji foo (np sprawdzić, czy void foo<5>() jest członkiem) w następujący sposób:

template < typename _class, int _n > 
class foo_int_checker { 

    template < typename _t, void (_t::*)() > 
    struct sfinae { }; 

    template < typename _t > 
    static big 
    test(sfinae< _t, &_t::foo<_n> > *); 

    template < typename _t > 
    static small 
    test(...); 

public: 

    enum { value = sizeof(test<_class>(0)) == sizeof(big) }; 

}; 

Następnie zrobić foo_int_checker< some_class, 5 >::value sprawdzić czy some_class ma człon void foo<5>(). Jednak na MSVC++ 2008 to zawsze zwraca false natomiast g ++ daje następujące błędy składniowe w wierszu test(sfinae< _t, &_t::foo<_n> >);

test.cpp:24: error: missing `>' to terminate the template argument list 
test.cpp:24: error: template argument 2 is invalid 
test.cpp:24: error: expected unqualified-id before '<' token 
test.cpp:24: error: expected `,' or `...' before '<' token 
test.cpp:24: error: ISO C++ forbids declaration of `parameter' with no type 

Oba wydają się niepowodzeniem, ponieważ staram się uzyskać adresu konkretyzacji funkcji szablon z typem, który sam parametr szablonu. Czy ktoś wie, czy jest to możliwe, czy z jakiegoś powodu jest zabronione przez standard?

EDYCJA: Wygląda na to, że pominięto składnię ::template, aby uzyskać g ++, aby poprawnie skompilować powyższy kod. Jeśli zmienię bit, w którym otrzymam adres funkcji na &_t::template foo<_n>, program kompiluje, ale otrzymuję to samo zachowanie, co MSVC++ (value jest zawsze ustawione na false).

Gdybym zakomentuj ... przeciążenie test aby zmusić kompilator, aby wybrać drugi, pojawia się następujący błąd kompilatora g ++ w:

test.cpp: In instantiation of `foo_int_checker<A, 5>': 
test.cpp:40: instantiated from here 
test.cpp:32: error: invalid use of undefined type `class foo_int_checker<A, 5>' 
test.cpp:17: error: declaration of `class foo_int_checker<A, 5>' 
test.cpp:32: error: enumerator value for `value' not integer constant 

gdzie linia 32 jest linia enum { value = sizeof(test<_class>(0)) == sizeof(big) };. Niestety, to nie wydaje mi pomóc zdiagnozować problem :(MSVC++ daje podobny błąd nieokreślony..

error C2770: invalid explicit template argument(s) for 'clarity::meta::big checker<_checked_type>::test(checker<_checked_type>::sfinae<_t,&_t::template foo<5>> *)' 

na tej samej linii

Co dziwne jest to, że jeśli dostanę adres ze specyficznym klasy, a nie parametr szablonu (tj. raczej niż &_t::template foo<_n> I do &some_class::template foo<_n>), a następnie otrzymuję prawidłowy wynik, ale wtedy moja klasa kontrolera jest ograniczona do sprawdzania pojedynczej klasy (some_class) dla funkcji. Ponadto, jeśli zrobię co następuje:

template < typename _t, void (_t::*_f)() > 
void 
f0() { } 

template < typename _t > 
void 
f1() { 
    f0< _t, &_t::template foo<5> >(); 
} 

i zadzwoń pod numer f1<some_class>(), a następnie NIE otrzymuję błędu kompilacji na &_t::template foo<5>. Sugeruje to, że problem powstaje tylko podczas pobierania adresu funkcji szablonu z typu, który sam jest parametrem szablonu, podczas gdy w kontekście SFINAE. Argh!

+0

C++ wysłano za 5 lat: D Zobacz http://stackoverflow.com/questions/36780867/i-neet-to-know-at-compilation-time-if-class-a-has- a-funkcja-członek-na-b/36780868 # 36780868 –

Odpowiedz

1

Jest coś podobnego już zaimplementowanego w Boost.MPL, nazywa się "BOOST_MPL_HAS_XXX_TRAIT_DEF".Zobacz:

http://www.boost.org/doc/libs/1_41_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html

To może wykryć, czy dana klasa zostały nazwane typ.

Również dla konkretnego przypadku, zamiast przekazywać wskaźnik funkcji jako parametr (void ('t :: *)()), spróbuj użyć go w ciele swojej metody, czyli coś podobnego:

template < typename _t > 
static big test(sfinae<_t>) 
{ 
    &_t::foo<_n>; 
} 
+0

Dzięki za link doładowania MPL. Chociaż nie wydają się wykrywać funkcji, ich metoda jest podobna i może obejść problem, który mam. Właśnie mam do wybrania ich makr teraz :) Myślę, że wskaźnik funkcji musi być uzyskany jako część sygnatury metody, aby kompilator używał go do zabezpieczenia przed przeciążeniem. Kiedy przenosiłem to do metody, kompilator zawsze wybiera "duże" przeciążenie testu, więc "wartość" jest prawdziwa, nawet jeśli funkcja nie istnieje. – Aozine

Powiązane problemy