2013-06-07 15 views
16

Ten problem był już omawiany kilka razy, ale wszystkie znalezione przeze mnie rozwiązania albo nie działały, albo były oparte na statycznym dowodzie doładowania. Mój problem jest prosty. Mam klasę i chcę tylko zezwolić na prawdziwe typy (podwójne i zmienne). Chcę, aby wystąpił błąd podczas kompilacji, gdy próbuję utworzyć instancję klasy z typem innym niż float lub double. Używam Visual C++ 11. Oto, co próbowałem:Jak ograniczyć klasę szablonów do określonych typów wbudowanych?

template <typename RealType> 
class A 
{ 
    // Warning C4346 
    static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value); 
} 


template <typename RealType> 
class A 
{ 
    // Error C2062: type 'unknown' unexpected 
    static_assert(decltype(RealType) == double || decltype(RealType) == float); 
} 

Wszelkie pomysły? Z góry dziękuję!

+1

Pierwsze pytanie brzmi, czy to ma znaczenie? Jeśli tworzysz szablon z innym typem, a typ nie może być traktowany tak, jak szablon oczekuje, że go potraktuje, kompilacja się nie powiedzie. A jeśli to możliwe, pozwalając * tylko * te dwa typy skutecznie zakazują ... powiedzmy ... typ taki jak BigDecimal. – cHao

+0

Visual Studio naprawdę wydaje ostrzeżenie, gdy static_assert nie działa, a nie błąd? Brzmi jak błąd. –

+0

Zobacz także [szablony C++, które akceptują tylko niektóre typy] (http://stackoverflow.com/q/874298/) i [Ogranicz parametr szablonu C++ do podklasy] (http://stackoverflow.com/q/3175219).One wyprzedzają C++ 11, ale mogą zrobić dobry marker dla kogoś innego. – jww

Odpowiedz

12

Jednym z rozwiązań, które widziałem jest użycie std::enable_if w aliasie typu. Coś jak:

using value_type = typename std::enable_if< 
        std::is_same<float, RealType>::value || 
        std::is_same<double, RealType>::value, 
        RealType 
       >::type; 

value_type istnieje tylko jeśli RealType jest dokładnie float lub double. W przeciwnym razie typ jest niezdefiniowany, a kompilacja nie powiedzie się.

Ostrzegam jednak, że jestem zbyt surowy w stosunku do typów. Szablony są tak potężne, jak częściowo dlatego, że pisanie przez kaczkę oznacza, że ​​każdy typ, który może być użyty w taki sposób, w jaki chcesz go użyć, zadziała. Niedozwolone typy ze względu na niedozwolone typy zazwyczaj nie zyskują dużo i mogą sprawić, że rzeczy będą mniej elastyczne niż mogłyby. Na przykład nie można użyć typu z większą precyzją, na przykład typu z dużym dziesiętnym.

+0

To, a jeśli potrzebujesz tylko dwóch specjalizacji, dobry stary polimorfizm OO i runtime może być lepszym pomysłem (przynajmniej wartym rozważenia). –

+0

SFINAE jest naprawdę dobra, gdy chcesz utworzyć więcej specjalizacji szablonu później :) Jednak jeśli zhe na pewno nie będzie żadnej innej specjalizacji, 'static_assert' pozwala wyświetlać sensowne komunikaty o błędach (ponieważ SFINAE często ranią mi oczy). – Morwenn

26

W swoim pierwszym przykładzie static_assert należy wziąć drugi parametr, który byłby ciąg dosłowny, w przeciwnym razie uznaje się to niepowodzeniem (edit: upuszczenie drugi parametr jest legalne ponieważ C++ 17). I ten drugi argument nie może być domyślny.

Twój Drugim przykładem jest niepoprawna z kilku powodów:

  • decltype ma być stosowany na wyraz, a nie na typ.
  • Po prostu nie można porównywać typów z ==, prawidłowym sposobem na to jest próba pierwszej próby z std::is_same.

więc właściwa droga do tego, co staramy się osiągnąć to:

#include <type_traits> 

template <typename RealType> 
class A 
{ 
    static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value, 
       "some meaningful error message"); 
}; 

Ponadto, założę się, starają się dusić szablon do pływających punktów wartości. W tym celu można użyć cechę std::is_floating_point:

#include <type_traits> 

template <typename RealType> 
class A 
{ 
    static_assert(std::is_floating_point<RealType>::value, 
       "class A can only be instantiated with floating point types"); 
}; 

I jako bonus, wziąć this online example.

5

ten sposób umożliwia również specjalizację różnych typów:

template<typename T, typename Enable = void> 
class A { 
/// Maybe no code here or static_assert(false, "nice message"); 
}; 

/// This specialization is only enabled for double or float. 
template<typename T> 
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> { 

}; 
+1

z 'static_assert (false," nice message ");' program jest źle sformułowany, nie jest wymagana żadna diagnostyka. Zobacz http://stackoverflow.com/questions/30078818/static-assert-dependent-on-non-type-template-parameter-different-behavior-on-gc Problem na początku wygląda na bardziej złożony, ale główną przyczyną jest tak prosty jak twój przykład. – bolov

Powiązane problemy