2010-09-10 15 views
12

Tengo dos estructuras:const-dad como parámetro de plantilla

// ----- non-const ----- 
    struct arg_adapter 
    { 
     EArgType type; // fmtA, fmtB, ... 

     union 
     { 
     TypeA * valueA; 
     TypeB * valueB; 
     // ... more types 
     } 

     arg_adapter(TypeA & value) : type(fmtA), valueA(&value) {} 
     arg_adapter(TypeB & value) : type(fmtB), valueB(&value) {} 
     // ... 
    } 

    // ----- const version ----- 
    struct const_arg_adapter 
    { 
     EArgType type; // fmtA, fmtB, ... 

     union 
     { 
     TypeA const * valueA; 
     TypeB const * valueB; 
     // ... more types 
     } 

     arg_adapter(TypeA const & value) : type(fmtA), valueA(&value) {} 
     arg_adapter(TypeB const & value) : type(fmtB), valueB(&value) {} 
     // ... 
    } 

se supone que deben usarse en métodos tales como:

Convert(const_arg_adapter from, arg_adapter to) 

Hay Typex múltiple'(aproximadamente 5, puede llegar a ser más), la mayoría de ellos primitivos. Esto es para evitar mantener diferentes prototipos.

Ahora mi pregunta ;-)

¿Hay una manera de hacer la const-ness un parámetro de plantilla? Mi objetivo es mantener una sola estructura, es decir

template <Qualifier CONSTNESS> 
struct arg_adapter_t 
{ 
    ... 
    CONSTNESS TypeA * valueA; 
    ... 
} 

Respuesta

6

se puede hacer aceptar una metafunction y se puede aplicar cualquier transformación te gusta

template<template<typename> class F> 
struct arg_adapter 
{ 
    EArgType type; // fmtA, fmtB, ... 

    union 
    { 
     typename F<TypeA>::type * valueA; 
     typename F<TypeB>::type * valueB; 
     // ... more types 
    }; 

    arg_adapter(typename F<TypeA>::type & value) : type(fmtA), valueA(&value) {} 
    arg_adapter(typename F<TypeB>::type & value) : type(fmtB), valueB(&value) {} 
    // ... 
}; 

typename arg_adapter<boost::add_const> const_adapter; 
typename arg_adapter<boost::mpl::identity> nonconst_adapter; 

O acepte un metafunction class para obtener más flexibilidad (incluida la capacidad de hacer que F tenga argumentos predeterminados desconocidos para su arg_adapter y tal.

template<typename F> 
struct arg_adapter 
{ 
    EArgType type; // fmtA, fmtB, ... 

    union 
    { 
     typename apply<F, TypeA>::type * valueA; 
     typename apply<F, TypeB>::type * valueB; 
     // ... more types 
    }; 

    arg_adapter(typename apply<F, TypeA>::type & value) : type(fmtA), valueA(&value) {} 
    arg_adapter(typename apply<F, TypeB>::type & value) : type(fmtB), valueB(&value) {} 
    // ... 
}; 

typename arg_adapter< lambda< boost::add_const<_> >::type > const_adapter; 
typename arg_adapter< lambda< boost::mpl::identity<_> >::type > nonconst_adapter; 
+0

Quizás, además de agregar un 'typedef', se evite repetir' typename apply :: type' demasiado :) –

+0

@Matthieu en C++ 0x, podríamos decir 'apply &'. Voy a adorar los alias de la plantilla :) –

+0

, así que lo haré, yo también :) Estoy esperando ansiosamente el alias de plantilla y las plantillas variadic, solo me pregunto qué compilador lo hará primero:/ –

0

Tal vez no lo entiendo, pero ¿por qué no puede usted utilizar

Convert(**const** arg_adapter from, arg_adapter to) 

Declarar un typedef para simplificar el trabajo

+0

"El constness del objeto apuntado es una propiedad del argumento de plantilla". Esto no se trata de punteros de const aquí. – Wok

+0

Necesito llamar a Convert con '(const TypeA &, TypeB &)', y arg_adapter no tiene CTor para 'const TypeA &'. – peterchen

7

Me tropecé sobre una mejor manera de utilizar el tipo de presentend selección Ideom por Alexandrescu en "Modern C Diseño ++":

Este es el selector del tipo:

template<bool flag, typename T, typename U> 
struct Select { typedef T Result; } 

template<typename T, typename U> 
struct Select<false, T, U> { typedef U Result; } 

Su clase se luego se vería así:

template<bool isConst> 
struct arg_adapter 
{ 
    // define A and B as const or non-const 
    typedef typename Select<isConst, const TypeA, TypeA>::Result A; 
    typedef typename Select<isConst, const TypeB, TypeB>::Result B; 

    EArgType type; // fmtA, fmtB, ... 

    union 
    { 
    A * valueA; // this is either const TypeA* oder TypeA* depending on 
       // your choice of the isConst template parameter 
    B * valueB; 
    // ... more types 
    } 

    arg_adapter(A & value) : type(fmtA), valueA(&value) {} // same here with ref 
    arg_adapter(B & value) : type(fmtB), valueB(&value) {} 
    // ... 
} 

Puede usar typedefs para mayor comodidad:

struct nonconst_adapter : public arg_adapter<false> {}; 

struct const_adapter : public arg_adapter<true> {}; 

Esta fue mi respuesta anterior usando rasgos de tipo simple:

template<typename TypeTraits> 
struct arg_adapter 
{ 
    typedef typename TypeTraits::T T; 
    void bar(T a) { ... } // by value/reference 
    void bar(T* a) { ... } // by pointer 
} 

template<typename K> 
struct NonConstTraits { 
    typedef K T; 
} 

template<typename K> 
struct ConstTraits { 
    typedef const K T; 
} 

template<typename K> 
struct nonconst_adapter : public arg_adapter<NonConstTraits<K> > {}; 

template<typename K> 
struct const_adapter : public arg_adapter<ConstTraits<K> > {}; 
+0

gracias por la respuesta - ilustra bien qué solución de Johannes usa boost. --- No terminé usándolo, ya que la cantidad de código con todos los typedefs era abotu el mismo (y en un caso de suma, algunos otros lugares deben actualizarse de todos modos). Aún así, crecí más seguro de TMP. – peterchen

Cuestiones relacionadas