Ce problème a été discuté plusieurs fois, mais toutes les solutions que j'ai trouvées n'ont pas fonctionné ou étaient basées sur l'assertion statique de boost. Mon problème est simple. J'ai une classe et je veux seulement autoriser les vrais types (double et float). Je veux une erreur de compilation si j'essaie d'instancier la classe avec un type autre que float ou double. J'utilise Visual C++ 11. Voici ce que j'ai essayé:
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);
}
Des idées? Merci d'avance!
Une solution que j'ai vue consiste à utiliser std::enable_if
dans un alias de type. Quelque chose comme:
using value_type = typename std::enable_if<
std::is_same<float, RealType>::value ||
std::is_same<double, RealType>::value,
RealType
>::type;
value_type
n'existe que si RealType
est exactement float
ou double
. Sinon, le type n'est pas défini et la compilation échoue.
Je vous préviens cependant d'être trop strict avec les types. Les modèles sont aussi puissants qu'ils le sont en partie parce que la saisie de canard qu'ils font signifie que tout type qui peut être utilisé comme vous le souhaitez, fonctionnera. Interdire les types pour les interdire ne vous rapporte généralement pas grand-chose et peut rendre les choses moins flexibles qu'elles ne pourraient l'être. Par exemple, vous ne pourriez pas utiliser un type avec plus de précision, comme un type à grande décimale.
Dans votre premier exemple, static_assert
devrait prendre un second paramètre qui serait un littéral de chaîne, sinon il est réputé échouer ( edit: la suppression du second paramètre est légale puisque C + +17). Et ce deuxième argument ne peut pas être utilisé par défaut.
Votre deuxième exemple est incorrect pour plusieurs raisons:
decltype
est destiné à être utilisé sur une expression, pas sur un type.==
, la bonne façon de procéder est ce que vous essayez lors de votre première tentative avec std::is_same
.Donc, la bonne façon de faire ce que vous essayez de réaliser est:
#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");
};
De plus, je parie que vous essayez de restreindre votre modèle à des valeurs à virgule flottante. Pour ce faire, vous pouvez utiliser le trait 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");
};
Et en bonus, prenez cet exemple en ligne .
De cette façon, il permet également une spécialisation pour différents types:
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> {
};