1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
/* deux "tags" : le premier représente le fait que l'on veut un pointeur, le deuxième représente le fait qu'on veut une valeur */
struct PointerTag{};
struct ValueTag{};
/* un trait permettant de définir le type de la donnée interne */
template <typename T, typename TAG>
struct TestTrait{
using ValueType = T;
};
/* et sa spécialisation pour le cas où l'on veut un pointeur */
template <typename T>
struct TestTrait<T, PointerTag>{
using ValueType = std::unique_ptr<T>;
};
/* une structure qui défini la manière de créer l'objet */
template <typename T, typename TAG>
struct ValueConstructor{
T operator()(T v){
return v;
}
};
/* la même structure mais spécialisée pour représenter un pointeur */
template <typename T>
struct ValueConstructor<T, PointerTag>{
using ValueType = typename TestTrait<T,PointerTag>::ValueType;
ValueType operator()(T v){
return std::make_unique<T>(v);
}
};
template <typename T, typename TAG = ValueTag>
class Test{
/* un alias de type représentant le type de la donnée sous-jacente
* ce sera soit une donnée "normale", soit un pointeur intelligent
* en fonction du paramètre transmis à TAG
*/
using ValueType = typename TestTrait<T, TAG>::ValueType;
/* un alias de type sur le foncteur qui créera la donnée sous-jacente
*/
using Ctor = ValueConstructor<T, TAG>;
public:
/* constructeur spécifiquement utilisé si on utilise la donnée et non le pointeur
* "il n'y a qu'à" initialiser la donnée
*/
template <typename U= TAG>
Test(T v, typename std::enable_if<std::is_same<U, ValueTag>::value>::type * =nullptr):value_(Ctor()(v)){
}
/* constructeur spécifiquement utilisé si on veut utiliser un pointeur
* La copie d'un std::unique_ptr étant désactivée, il faut utiliser la sémantique de déplacement
*/
template <typename U= TAG>
Test(T v, typename std::enable_if<std::is_same<U, PointerTag>::value>::type * =nullptr):value_(std::move(Ctor()(v))){
}
template <typename U= TAG>
T value( typename std::enable_if<std::is_same<U, ValueTag>::value>::type * =nullptr) const{
return value_;
}
template <typename U= TAG>
T value( typename std::enable_if<std::is_same<U, PointerTag>::value>::type * =nullptr) const{
return *(value_.get());
}
private:
/* la donnée sous-jacente... une donnée "normale" si TAG = ValueTag,
* un pointeur intelligent si TAG = PointerTag
*/
ValueType value_;
};
/* le tout sera utilisé sous la forme de */
int main(){
Test<int> value(5); // la donnée sous-jacente est une donnée "classique"
Test<int, PointerTag> ptr(10); // la donnée sous-jacente est un pointeur
std::cout<<"value.value() == "<<value.value() <<"\n"
<<"ptr.value() == "<<ptr.value() <<"\n";
return 0;
} |
Partager