J'ai donc une fonction que j'utilise pour vérifier les valeurs et lever une exception si la valeur n'est pas valide, sinon renvoyer la valeur telle qu'elle a été reçue. J'essaie de généraliser cette routine avec des révérences universelles et des traits de type. Je sens que je suis proche car mon exemple fonctionne dans certains cas, mais pas tous. Il semble ne fonctionner qu'avec des valeurs.Problèmes avec le type-caractère conditionnel Référence universelle
#include <iostream>
#include <utility>
#include <type_traits>
#include <string>
#include <vector>
using namespace std;
struct error_type{};
template <class T>
class has_empty
{
template<class U, class = typename std::enable_if<std::is_member_pointer<decltype(&U::empty)>::value>::type>
static std::true_type check(int);
template <class>
static std::false_type check(...);
public:
static constexpr bool value = decltype(check<T>(0))::value;
};
template <bool invalid>
struct valid {};
template <>
struct valid<false>
{
template<typename U, typename E>
static inline U&& check(U&& toCheck, const E& toThrow)
{
if (!toCheck)
std::cout << "NoEmpty Throw" << '\n';
else
std::cout << "NoEmpty valid" << '\n';
return std::forward<U>(toCheck);
}
};
template <>
struct valid<true>
{
template<typename U, typename E>
static inline U&& check(U&& toCheck, const E& toThrow)
{
if (toCheck.empty())
std::cout << "HasEmpty Throw" << '\n';
else
std::cout << "HasEmpty valid" << '\n';
return std::forward<U>(toCheck);
}
};
template<typename T
, typename E
, typename = typename std::enable_if<std::is_base_of<error_type, E>::value>::type>
inline T&& do_check(T&& toCheck, const E& toThrow)
{
return valid<has_empty<T>::value>::check(std::forward<T>(toCheck), toThrow);
}
struct HasEmpty
{
bool empty() {return false;}
};
struct NoEmpty
{
};
int main()
{
error_type e;
cout << has_empty<std::wstring>::value << '\n';
cout << has_empty<std::vector<std::wstring>>::value << '\n';
cout << has_empty<int>::value << '\n';
cout << has_empty<HasEmpty>::value << '\n';
cout << has_empty<NoEmpty>::value << '\n';
do_check(true, e);
do_check(false, e);
do_check(std::string("45"), e);
do_check(HasEmpty(), e);
do_check(std::vector<bool>(), e);
HasEmpty he;
do_check(std::move(he), e);
//do_check(he, e); // does not work, has_empty<T>::value is 0
}
produit la sortie
1
1
0
1
0
NoEmpty valid
NoEmpty Throw
HasEmpty valid
HasEmpty valid
HasEmpty Throw
HasEmpty valid
Si je décommenter la dernière ligne, je reçois l'erreur suivante:
prog.cpp: In instantiation of 'static T&& valid<false, T, E>::check(T&&, const E&) [with T = HasEmpty&; E = error_type]':
prog.cpp:56:84: required from 'T&& do_check(T&&, const E&) [with T = HasEmpty&; E = error_type; <template-parameter-1-3> = void]'
prog.cpp:87:19: required from here
prog.cpp:30:11: error: no match for 'operator!' (operand type is 'HasEmpty')
if (!toCheck)
^
prog.cpp:30:11: note: candidate is:
prog.cpp:30:11: note: operator!(bool) <built-in>
prog.cpp:30:11: note: no known conversion for argument 1 from 'HasEmpty' to 'bool'
qui semble que has_empty<T>::value
évalue à false
. Je suis sûr que je pourrais faire un travail différent pour que cela fonctionne, donc à ce stade c'est un peu académique. Cependant, toute aide serait appréciée.
Merci! ça fonctionne comme un charme. Je suis encore confus quant à pourquoi, je comprends que le type est déduit à une référence, et cela est souhaité, mais pourquoi une référence n'aurait pas la fonction membre? Aussi, merci pour la réponse rapide. – Apeiron
@Apeiron Seuls les types de classe ont des fonctions membres, les types de références n'en ont pas. Je ne sais pas comment l'expliquer mieux, peut-être [ces messages d'erreur] (http://coliru.stacked-crooked.com/a/7f64db6fae3b4084) vous aidera à comprendre. – Praetorian
Est-ce qu'une référence dans son contexte fonctionne comme un pointeur? Je sais qu'un pointeur est juste une adresse de mémoire, mais j'ai toujours pensé que les références n'étaient que des alias et que, à toutes fins utiles, c'était la même chose que la non-référence. Cela ressemble à des traits de type pour une référence qui sont plus proches de ceux d'un pointeur que d'une classe. Merci pour l'explication, c'était très utile. – Apeiron