2009-11-19 12 views
7

Tutaj mam funktora rodzaju obserwacji:Jak zmniejszyć liczbę argumentów szablonu?

template<class T, class Foo, T Foo::*p> 
struct X { 
    void operator()(Foo & f) { 
     (f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()` 
    } 

}; 

i próbki struct:

struct FF 
{ 
    int m; 
    int r; 
}; 

chcę użyć funktora X, ale nie chcę, aby jednoznacznie określić szablon argumentu następująco :

void testforx() 
{ 
    std::vector<FF> cont(5); 
    std::for_each(cont.begin(), cont.end(), X<int, FF, &FF::r>()); // it work, but I don't want to write `int` and `FF` 
    std::for_each(cont.begin(), cont.end(), createx<&FF::r>());  // how I would like to use it, how to declare `createx` function? 
} 

Oto co próbowałem bez powodzenia:

// that is what I tried, but it could not deduce T and Foo 
template<T Foo::*p, class T, class Foo> 
X<T, Foo, T Foo::*p> createx() 
{ 
    return X<T, Foo, p>(); 
} 

// this works, but requires to write T and Foo explicitly 
template<class T, class Foo, T Foo::*p> 
X<T, Foo, T Foo::*p> createx() 
{ 
    return X<T, Foo, p>(); 
} 
+0

Mała poprawka (twój "poprawny" kod nie kompiluje się): twoja deklaracja typu powrotu 'createx' powinna zawierać' p' jako trzeci parametr szablonu, a nie 'T Foo :: * p'. Nie zmienia jednak problemu. –

Odpowiedz

8

prostu nie przechowywać wskaźnik użytkownika jako argument szablonu:

template<class T, class Foo> 
struct X { 
    X(T Foo::*p): p(p) {} 
    void operator()(Foo & f) { 
     (f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()` 
    } 
private: 
    T Foo::*p; 
}; 

template <class T, class Foo> 
X<T, Foo> MakeX(T Foo::*p) 
{ 
    return p; 
} 

I nie sądzę, że jest możliwe, aby wywnioskować typy z podejściem: nie można użyć wskaźnika do -member przekazywany do funkcji, w której występuje odliczanie typu.

Edytuj: Jednak mogą istnieć rozwiązania oparte na makrach.

Na przykład, można utworzyć klasę, do utworzenia instancji X, podobnie jak to:

template <class T, class Foo> 
struct XMaker 
{ 
    template <T Foo::*p> 
    X<T, Foo, p> make() { return X<T, Foo, p>(); } 
}; 

Teraz można utworzyć marki ... funkcję wyprowadzić T i Foo:

template <class T, class Foo> 
XMaker<T, Foo> make_x_maker(T Foo::*) 
{ 
    return XMaker<T, Foo>(); 
} 

co pozwala napisać makro jak:

#define CREATE_X(member) make_x_maker(member).make<member>() 

Zastosowanie:

std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r)); 
+0

Jest to kod czasowo krytyczny. Nie chcę przechowywać 'p'. –

+2

Pytanie brzmiało, jak napisać 'createx'. Mam już działające rozwiązanie kompilacyjne i po prostu chcę zmniejszyć liczbę argumentów szablonu. –

+0

Teraz jest to prawie potrzebne. Przyjmuję tę odpowiedź, ale nie lubię makr. –

1

Nie sądzę, że możliwe jest zmniejszenie liczby argumentów szablonu, które należy określić, jeśli chcesz, aby arbitralny wskaźnik funkcji członka był argumentem szablonu.

Zamiast funkcji członka Wskaźniki można użyć zwykłego parametr typu dla funktora że wydobywa odniesienie:

template<typename Func> 
class X 
{ 
public: 
    explicit X(Func f = Func()) : f(f) {} 

    template<class K> 
    void operator()(K & k) const { 
     f(k) = 12 * f(k); 
    } 
private: 
    Func f; 
}; 

Następnie, wciąż masz możliwość używania specjalnego funktor że bezpośredni dostęp do niektórych państw (jeśli uważasz, że zapewnia to lepszą wydajność) lub użyj bardziej ogólnego funktora dostępnego, który robi to za pomocą wskaźnika funkcji członka jako członka.

+2

Jest to dozwolone przez Standardowy wskaźnik funkcji członka jako argument szablonu. –

+1

Tak, wiem. "Nie sądzę, że to możliwe" odnosi się do tytułu pytania. Nie powiedziałem "wskaźniki funkcji członków nie są dozwolone jako parametry szablonu". Przeczytaj uważnie odpowiedzi, zanim przejdziesz do porządku. Postaram się zrobić co w mojej mocy następnym razem, aby pisać odpowiedzi, których nie można źle zrozumieć. Dzięki. – sellibitze

+0

Ta odpowiedź nie ma nic wspólnego z moim pytaniem. –

1

Mam jedno pytanie: czy naprawdę trzeba podać wszystkie te argumenty?

struct XR 
{ 
    template <class Foo> 
    void operator()(Foo& foo) const { foo.r = 12 * foo.r; } 
}; 

To działa, nie ma potrzeby dodatkowego make metody po prostu działa:

void testforx() 
{ 
    std::vector<FF> cont(5); 
    std::for_each(cont.begin(), cont.end(), XR()); 
} 

wolę nie być zbyt ogólne podczas tworzenia szablonów.

Jeśli potrzebujesz bardziej złożonego operator(), zawsze możesz wykonać ciężki lifting WEWNĄTRZ go.

Możesz także wziąć pod uwagę Boost.Bind, jeśli naprawdę chcesz wyodrębnić funkcje wskaźnika i odniesienia do atrybutów.

EDIT:

Mam pomysł, który będzie nieco inna i nie pociąga za sobą żadnych makro magii, ani nawet żadnej magii METAPROGRAMOWANIE.

Dlaczego nie po prostu użyć typedef i zrobić z nim?

OK, może nie być tak zautomatyzowany, jak chcesz ... ale musisz tylko wpisać ten jeden raz, mimo wszystko.

typedef X<int,FF,&FF::m> X_FF_m; // once 

std::for_each(cont.begin(), cont.end(), X_FF_m()); 

wydaje się mniej pisania niż

std::for_each(cont.begin(), cont.end(), createX<&FF::m>()); 

powtarzany wielokrotnie.

Ledwo używam nagich szablonów w moim kodzie, wolę je poprawiać, aby poprawić czytelność.

+0

To nie jest żadna opcja. 'struct XR' używa' .r'-member. Jeśli chcę używać elementu '.m', czy muszę zdefiniować nową' struct XM'? A co z innymi członkami? –

+0

Jedna struktura na członka, nic nadzwyczajnego, po prostu coś, co działa i jest proste. Oczywiście w twoim przykładzie przedstawiłeś strukturę z 2 atrybutami i myślę, że skaluje się ona całkiem dobrze do 4 lub 5 ... –

Powiązane problemy