Autor Wątek: std::enable_if na podstawie wartości enum'a  (Przeczytany 1496 razy)

Offline Icy Tower

  • Użytkownik

# Luty 20, 2016, 22:10:48
Staram się stworzyć wzorzec klasy, który przyjmuje dwa parametry typu enum. Zależnie od wartości enuma chcę włączyć lub wyłączyć określone metody. Np pewien getter ma sens tylko wtedy, gdy enum ma określoną wartość.

Można to rozwiązać poprzez specjalizację wzorca dla każdej kombinacji parametrów wzorca, ale tych kombinacji jest kilkadziesiąt, więc szukam innego wyjścia.

Pomyślałem, że można do tego użyć std::enable_if - ale ono chyba służy do sprawdzenia typów parametrów a nie ich wartości?

Czy da się to jakoś elegancko rozwiązać?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline karol57

  • Użytkownik

# Luty 20, 2016, 22:37:05
O to chodzi?
Kod: (C++11) [Zaznacz]
#include <type_traits>

enum MY_ENUM {
ME_VAL_1,
ME_VAL_2,
ME_VAL_3
};

template<MY_ENUM meow>
class MyClass {
public:
template<MY_ENUM meow2 = meow>
typename std::enable_if<meow2 == ME_VAL_1, int>::type
getter() {
return 5;
}

int other_func() {
return 6;
}
};

#include <iostream>
using std::cout;
using std::endl;

int main() {
MyClass<ME_VAL_1> mcv1;
MyClass<ME_VAL_2> mcv2;
MyClass<ME_VAL_3> mcv3;

cout << mcv1.getter() << endl;
cout << mcv1.other_func() << endl;

// cout << mcv2.getter() << endl; // error
cout << mcv2.other_func() << endl;

// cout << mcv3.getter() << endl; // error
cout << mcv3.other_func() << endl;

return 0;
}

Offline Icy Tower

  • Użytkownik

# Luty 20, 2016, 22:49:54
Tak, o to mi chodziło. Tylko, że kiedy użyję wzorca dla takiego enum'a dla którego nie ma specjalizacji to jest błąd kompilacji (error C2893: Failed to specialize function template). A chciałbym, żeby tej metody po prostu wtedy nie było.

I czy można ten std::enable_if, który napisałeś zastosować także do konstruktora? Mam problem ze składnią...

Offline karol57

  • Użytkownik

  • +3
# Luty 20, 2016, 23:03:20
Napisze jak informatyk: "U mnie działa".
Rozwiązaniem tego problemu jest zrobienie osobnego wzorca dla funkcji poprzez template<MY_ENUM meow2 = meow> i użycie meow2 a nie meow. Brzydkie rozwiązanie, ale na inne nie mogę wpaść (a raczej za mało wiem o C++).

Co do konstruktora to "u mnie działa" coś takiego:
Kod: (C++11) [Zaznacz]
#include <type_traits>

enum MY_ENUM {
ME_VAL_1,
ME_VAL_2,
ME_VAL_3
};

template<MY_ENUM meow>
class MyClass {
public:
template<MY_ENUM meow2 = meow>
MyClass(typename std::enable_if<meow2 == ME_VAL_1>::type* empty = 0) :
dupa(10) {}
template<MY_ENUM meow2 = meow>
MyClass(typename std::enable_if<meow2 != ME_VAL_1>::type* empty = 0) :
dupa(0) {}

int get_dupa() { return dupa; }
private:
int dupa;
};

#include <iostream>
using std::cout;
using std::endl;

int main() {
MyClass<ME_VAL_1> mcv1;
MyClass<ME_VAL_2> mcv2;
MyClass<ME_VAL_3> mcv3;

cout << mcv1.get_dupa() << endl; // 10
cout << mcv2.get_dupa() << endl; // 0
cout << mcv3.get_dupa() << endl; // 0

return 0;
}

No i jak używasz C++14 to możesz zamiast enable_if używać enable_if_t, ale to pozostawiam jako ćwiczenie.
« Ostatnia zmiana: Luty 21, 2016, 01:54:37 wysłana przez karol57 »

Offline Icy Tower

  • Użytkownik

# Luty 20, 2016, 23:13:49
Dziękuję, bardzo mi pomogłeś!

Ten błąd kompilacji to właśnie informacja, że takiej metody nie ma - mój błąd.