Quelqu'un pourrait-il m'aider à faire en sorte que ma fonction n'accepte que les types d'argument que la fonction peut être appelée à l'intérieur?
J'ai une classe Logger qui peut être démarrée avec un HardwareSerial
objet dans la fonction setup ()
d'un code Arduino.
Ensuite, dans la loop ()
, je voudrais appeler la fonction Logger.print ()
qui ne devrait accepter que les arguments que HardwareSerial.print () code > peut être appelé.
Voici mes essais laids et qui ne fonctionnent pas:
template <typename... ARGS> size_t print(const ARGS &... args) { if (serial != NULL) { if (sizeof...(args) == 2) { return this->serial->print(args[0], args[1]); } else if (sizeof...(args) == 1) { return this->serial->print(args[0]); } } return 0; } template <typename T> size_t print(const T &t, typename std::enable_if<std::is_convertible<const __FlashStringHelper *, T>::value || std::is_base_of<const String &, T>::value || std::is_array<T>::value || //std::is_same<char[std::extent<T>::value], T>::value || std::is_same<char, T>::value || std::is_same<char *, T>::value || std::is_same<const char *, T>::value || std::is_same<unsigned char, T>::value || std::is_same<int, T>::value || std::is_same<unsigned int, T>::value || std::is_same<long, T>::value || std::is_same<unsigned long, T>::value || std::is_same<double, T>::value || std::is_convertible<const Printable &, T>::value || std::is_convertible<struct tm *, T>::value, T>::type * = 0) { if (serial != NULL) { return this->serial->print(t); } retrun 0; }
3 Réponses :
Détecter si une fonction peut être appelée est un jeu d'enfant lorsque vous utilisez decltype
pour la vérification SFINAE:
template <typename... ARGS> auto print(const ARGS &... args) -> decltype(this->serial->print(args...)) { if (serial != NULL) { return this->serial->print(args...); } return 0; }
La syntaxe pour l'extension de modèle variadique est
template <typename... ARGS> auto print(const ARGS&... args) -> decltype(this->serial->print(args...)) { if (serial != nullptr) { return this->serial->print(args...); } return 0; }
pour le rendre convivial pour SFINAE, vous pouvez utiliser:
template <typename... ARGS> size_t print(const ARGS&... args) { if (serial != nullptr) { return this->serial->print(args...); } return 0; }
Puisque vous voulez la même interface que HardwareSerial
, avec toutes les méthodes print
, println
et write
, votre classe Logger
doit hériter de Print
puis implémenter uniquement la méthode write (uint8_t)
qui n'appelle que les s HardwareSerial
write(uint8_t)
.
size_t Logger::write(uint8_t c) { if (this->serial != NULL) { return this->serial->write(c); } return 0; }
class Logger : public Print { public: virtual size_t write(uint8_t); }
En savoir plus sur la classe Print
: https://playground.arduino.cc/Code/Printclass