| 12
 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