2012-04-25 16 views
5

Estaba pensando en una clase como:¿Cómo puedo definir condicionalmente el constructor predeterminado?

template < typename ...Whatever > 
class MyClass 
{ 
public: 
    static constexpr bool has_default_ctr = Something; 

    // I want this only if "has_default_ctr" is "true". 
    MyClass(); 

    //... 
}; 

no creo que pueda usar una plantilla constructor y std::enable_if para esto (porque no hay argumentos). ¿Me equivoco? Si no, ¿hay alguna otra forma de hacer esto?

+0

Solo un pensamiento rápido - ¿Intentó 'enable_if' y un constructor con un argumento con un valor predeterminado? –

+2

¿Podría explicar por qué quiere hacer esto? –

+0

Ok, honestamente pensé que esto no era posible, me corrigieron y borré mi respuesta. ¿No es esto un gran patrón anti? – verhage

Respuesta

-1

puede utilizar diferentes constructores con diferentes argumentos

MyClass(){ 

} 
MyClass(int num){ 

} 
MyClass(String s){ 
} 

y se puede escribir sencilla y función estática que devuelve la clase y escribe las condiciones en el interior:

static chooseContructor(/*parameters*/){ 
if(/*something*/){ 
    return new MyCLass(); 
} 
else if(/*something else*/){ 
    return new MyClass(int num); 
} 
else if{ 
    return new MyClass(String s); 
} 
} 

Y así sucesivamente .. Algo así le dará un selector de constructor semiautomático

+0

Tho falla si 'MyClass' tiene miembros que no son predecibles. –

10

C++ 11 permite (confiablemente) usar enable_if al estilo de SFINAE en argumentos de plantilla:

template< 
    // This is needed to make the condition dependent 
    bool B = has_default_ctr 
    , typename std::enable_if<B, int>::type = 0 
> 
MyClass(); 

// When outside of class scope: 
// have to repeat the condition for out-of-line definition 
template<bool B, typename std::enable_if<B, int>::type = 0> 
MyClass::MyClass() 
/* define here */ 

En C++ 03 se podría haber utilizado un constructor con un parámetro unario en default - el parámetro por defecto significa que el constructor todavía cuenta como un constructor por defecto.

+0

Mi dios, este truco es muy útil para mí. Conocía std :: enable_if pero nunca pensé en usarlo de esa manera –

+0

Creo que esto da como resultado un error en tiempo de compilación. A menos que me falta algo, '' typename std :: enable_if :: type = 0' resolve a 'void = 0' cuando' B = true'? 'class C = typename std :: enable_if :: type' funcionaría. –

+0

@ void-pointer La sustitución produce 'int = 0'. –

0

Para obtener diferentes definiciones para una clase dependiendo de alguna condición, coloque el cálculo de dependencia en un argumento de plantilla.

// primary template, no default constructor unless Something is true 
template< typename T, bool has_default_ctr = Something > class MyClass { 
    // as you had it, with no default constructor 
}; 

// you want MyClass<T,true> to be just like MyClass<T,false> 
// but with a default constructor: 
template< typename T > class MyClass<T,true> : public MyClass<T,false> { 

    MyClass() : MyClass<T,false>(/* chosen constructor args */) { etc; } 

    using MyClass<T,false>::MyClass<T,false>; 
}; 

si usted no tiene C++ 11 no se puede utilizar la herencia constructor using y que tendrá que redeclare todas sus constructores y hacia adelante a lo largo de sus argumentos a la clase base.

Esto es de dedos a teclado, no tengo un compilador práctico en el cajero, por lo que es probable que haya menos sintaxis.

+0

@jhill No puedo hacer esta compilación en VS11. Tengo no hay soporte para constexpr – Ghita

+0

Esto no se compila: plantilla clase MiClase { }; plantilla clase MiClase:. MiClase pública { MiClase() {} }; – Ghita

1

Se podría hacer algo tan simple como

template < typename ...Whatever > 
class MyClass 
{ 
public: 
    static constexpr bool has_default_ctr = Something; 

    // I want this only if "has_default_ctr" is "true". 
    MyClass() 
    { 
     static_assert(has_default_ctr, "Not Default Constructible"); 
    } 

    //... 
}; 
1

Dado que la solución con un parámetro predeterminado se menciona en los comentarios, pero necesitaba bastante tiempo para encontrar la manera de hacerlo (hizo que mi clase Enabler privada , que no funciona), aquí la solución sugerida, en caso de que alguien lo está buscando:

class MyClass { 
public: 
    // if constructor is supposed to be public, 
    // this helper class must be public as well! 
    struct Enabler {}; 

    template <class U = Enabler> 
    MyClass (std::enable_if_t<has_default_ctr, U> = Enabler {}) 
    { 
     // whatever 
    } 
}; 
0

aquí es el que he usado recientemente. Necesitaba una plantilla de clase con un constructor predeterminado si sus miembros de datos admiten un constructor predeterminado, de lo contrario, el constructor predeterminado no debería compilar.

La plantilla de clase define un parámetro de tipo de plantilla, y la clase define un miembro de datos de ese tipo (una variante que use herencia también puede ser atractiva, ya que puede usar la optimización de clase base vacía). El constructor predeterminado de la clase llama automáticamente al constructor predeterminado del miembro de datos. Si el tipo del miembro de datos no tiene un constructor predeterminado, la compilación falla. De lo contrario, tiene éxito. Aquí está el código:

#include <string> 
template <typename Data> 
class Demo 
{ 
    Data d_data; 

    public: 
     Demo() = default;  // OK when used and Data has a default 
           // constructor. 

     Demo(Data const &data) // Exampe of an additional constructor 
     : 
      d_data(data) 
     {} 

     // ... 
}; 

struct WithoutDefault 
{ 
    WithoutDefault(int) 
    {} 
}; 

int main() 
{ 
    Demo<std::string> withString; 
    // Demo<NoDefault> nope;    // won't compile 

    WithoutDefault nod(10); 
    Demo<WithoutDefault> nodefault(nod); // OK 
} 
Cuestiones relacionadas