2011-09-12 11 views
7

En la actualidad, una de mis plantillas de clase juguete tiene dos constructores que son muy similares:la combinación de dos constructores que copiar y mover

optional(const T& x) 
{ 
    construct(x); 
} 

optional(T&& x) 
{ 
    construct(std::move(x)); 
} 

Puedo combinarlos en una plantilla constructor sola, o cambiará esto la semántica de alguna manera ?

template<typename U> 
optional(U&& x) 
{ 
    construct(std::forward<U>(x)); 
} 
+0

¿Cuál es la carne real de 'construir'? –

+0

@Alf: colocación fea cosas nuevas en el almacenamiento alineado :) – fredoverflow

Respuesta

2

cambia la forma en rasgos tales como std::is_constructible y std::is_convertible interactuar con optional . Por ejemplo dado:

class A {}; 

int main() 
{ 
    std::cout << std::is_constructible<optional<A>, int>::value << '\n'; 
}; 

Su código original imprimiría:

0 

Pero su nuevo código imprimirá:

1 

Si esto no es deseable, y todavía se desee vaya con su nuevo código, puede enable_if para restringir U a tipos aceptables.

El único otro posible problema que veo es si T puede ser un tipo de referencia (por ejemplo, int&).En ese caso, el segundo constructor de su código original parece sospechoso, ya que estaría pasando en un valor r, y es posible que esté tratando de vincular ese valor r a una referencia de valor l no const (no se puede decir con certeza). Si T nunca puede ser un tipo de referencia, no hay necesidad de preocuparse por esto.

4

Un constructor con plantilla nunca será (considerado por el compilador) un constructor de copia, lo siento.

+0

Erm, 'opcional (const T &)' ni siquiera es un constructor de copia, ¿en qué estaba pensando? editado – fredoverflow

+0

@Fred: en ese caso, considere usar el reenvío de constructor C++ 11? si aún está implementado por el compilador. no sé qué compiladores lo admiten, si es que hay alguno. alternativamente, si no se admite, puede usar una clase base artificial. reenviar las llamadas de constructor a la clase base. –

+0

Oh, 'construct' no es un constructor, es una plantilla de función miembro. – fredoverflow

1

Oh, construir no es un constructor, es una plantilla de función de miembros.

Entonces, posiblemente, la semántica es diferente. Su conjunto de sobrecarga original pasa una referencia lvalue a const o una referencia rvalue a non-const. La versión de plantilla puede pasar una referencia lvalue a no -const también. (Estoy haciendo caso omiso de las referencias a rvalue const.)

En toda verosimilitud, aunque construct se declara bien para aceptar U&& (de lo contrario su sobrecarga previa que mueve un T no funcionaría) y en este caso debe frente a los casos -const lvalues, o se declara que acepta U const& y en este caso es inofensivo.

0

Asumiendo que tiene al menos construct(const T& x) y posiblemente la adición de construct(T&& x) definido, y su objeto de tipo U es convertible a un objeto de tipo T, creo que debe estar bien ...

  1. Una constante referencia l-valor de tipo U se unirá a construct(const T& x)
  2. a no constante referencia l-valor de tipo U se unirá a construct(const T& x)
  3. a r-valor temporal del tipo U voluntad unirse a construct(T&& x) o construct(const T& x) si la versión de referencia r-valor no se define
  4. Una constante de referencia r-valor de tipo U se unirán a construct(const T& x)
Cuestiones relacionadas