2009-06-04 15 views
7

¿Hay alguna forma de comprobar en tiempo de compilación si alguna clase tiene un constructor con ciertos argumentos? ?Comprobar en tiempo de compilación firma de constructor de clase

Por ejemplo:

class foo { 
    foo(std::string &s) { 
    } 
}; 

Quiero comprobar en tiempo de compilación que el constructor con std :: string & siempre definido. Tal vez impulsar proporciona esa funcionalidad?

+0

¿Quieres decir sin intentar crear objetos? – Naveen

+1

Si usa este constructor mientras no está definido, el compilador generará un error. Si no lo usa, ¿por qué quiere que esté presente? –

+0

El caso de prueba interesante para cualquier comprobación propuesta es std :: string en sí. – MSalters

Respuesta

3

Si realmente lo necesita, puede agregar esta función:

static void _dummy() { std::string s; foo f(s); } 

Sin su constructor, la compilación fallará. Nota: su constructor es privado. Si es a propósito, entonces _dummy debe estar dentro de la clase. De lo contrario, puedes tenerlo fuera de la clase.

Además, puede templatar o incluso convertirlo en una macro, si esto sucede mucho en su código.

Pero, a decir verdad, todavía parece un truco. ¿Estás seguro de que lo necesitas?

0

Lo que está pidiendo suena como una prueba unitaria. Me gustaría descargar algo como cppunit e integrarlo en tu compilación.

Cualquier prueba de unidad que escriba se compilará/ejecutará en tiempo de compilación. Ver Unit Testing para más información.

+0

Las pruebas unitarias no están realmente en tiempo de compilación, y eso fue muy explícitamente preguntado. Ya hay 2 soluciones que demuestran que es bastante posible. – MSalters

+0

Las pruebas unitarias no son una verificación de tiempo de compilación, pero se pueden configurar para ejecutarse cuando compila el código. Esto le proporciona lo que probablemente esté buscando de todos modos, que es una forma de validar contratos funcionales y suposiciones sobre su código. ¿Hay alguna razón por la que esto deba suceder en tiempo de compilación? –

0

Si necesita este tipo de controles, es probable que tengas algún otro tiempo de compilación

sugiero echar un vistazo a impulsar el concepto de comprobar la biblioteca (documentación es here). Puede encontrar documentación, clases y macros que pueden ayudarlo.

3

Si está tratando de verificar si foo es construible a partir de una cadena, puede usar boost::is_convertible.

Por ejemplo:

BOOST_STATIC_ASSERT((boost::is_convertible<std::string, foo>::value)); 
2

Uso de la comprobación Concept en impulso 1.39:

#include <boost/concept_check.hpp> 

class foo_c 
{ 
public: 
    foo_c(std::string& s) 
    {} 
}; 

template<typename T> 
class algo_c 
{ 
BOOST_CONCEPT_ASSERT((boost::Convertible<std::string,T>)); 
public: 
    algo_c() 
    {} 
}; 

quitando o cambiando el constructor de resultado foo_c en el siguiente error de compilación tiempo:

error C2440: 'initializing' : cannot convert from 'std::string' to 'foo_c'

EDITAR: Eso se puede hacer para que funcione con un constructor explícito con un homem cheque concepto ade:

template <typename T> 
struct HasTheRightConstructor 
{ 
    BOOST_CONCEPT_USAGE(HasTheRightConstructor) 
    { 
     std::string v; 
     T j(v); 
    } 
}; 
+1

Este método no funciona para constructores explícitos. Funciona solo para constructores con 1 argumento no predeterminado. No funciona, si el operador de conversión se define de "std :: string" a T –

+0

Buen punto. Editado para que funcione con ctor explícito. No sé cómo hacer para que coincida con un prototipo preciso (no se puede hacer una respuesta de MSalters para compilar –

6

La forma más común para comprobar si existe una función específica es tomar su dirección y asignarla a una variable ficticia. Esto es mucho más preciso que las pruebas mencionadas hasta ahora, porque esto verifica la firma de la función exacta. Y la pregunta era específicamente sobre string& en la firma, por lo que no const y, por tanto, presumiblemente la modificación de la cadena.

Sin embargo, en este caso no puede usar el truco de tomar la dirección y asignar: los constructores no tienen direcciones. Entonces, ¿cómo verificas la firma entonces? Simplemente: hazte amigo en una clase ficticia.

template<typename T> 
class checkSignature_StringRef { 
    friend T::T(string&); 
}; 

Esto también es un proceso muy específico: ni siquiera coincidirá constructores similares como foo::foo(std::string &s, int dummy = 0).

+0

Eso no se compila con VC8: la clase contiene la anulación explícita 'T :: {ctor}' pero no deriva de una interfaz que contiene la declaración de función –

+0

, tenga en cuenta el informe de defectos aquí: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#215 –

+0

crash en gcc3! Error de compilación en gcc4 ... Eso El método se ve bien pero me gustaría saber que alguien más lo compiló ... –

1

Se me ocurrió un problema similar al querer reenviar constructores a la clase base cuando los argumentos son compatibles, y hacer otra cosa cuando no.

que aquí hay una rasgos generalizados trabajando en MSVC 2013 (requiere C++ 11 cosas):

namespace detail { 
    template<class type,class...Args> 
    class constructible_from 
    { 
     template<class C> 
     static C arg(); 

     template <typename U> 
     static boost::mpl::true_ constructible_test(U *, decltype(U(arg<Args>()...)) * = 0); 
     static boost::mpl::false_ constructible_test(...); 

    public: 

     typedef decltype(constructible_test(static_cast<type*>(nullptr))) result; 

    }; 
} // namespace detail 

template<class type> 
struct constructible 
{ 
    template<class...Args> 
    struct from : 
     detail::constructible_from<type,Args...>::result {}; 
}; 

Aquí está un ejemplo de uso rasgos, dejo el enable_if aplicación como un ejercicio: D:

struct b{}; 
struct c{}; 
struct d : c{}; 

struct a 
{ 
    a() {} 
    a(a &) {} 
    a(b,c) {} 
    a(c) {} 
}; 


static_assert(
    constructible<a>::from<>::value, 
    "a()" 
); 
static_assert(
    constructible<a>::from<a&>::value, 
    "a(a&)" 
); 
static_assert(
    ! constructible<a>::from<const a&>::value, 
    "a(const a&)" 
); 
static_assert(
    constructible<a>::from<b,c>::value, 
    "a(b,c)" 
); 
static_assert(
    ! constructible<a>::from<b>::value, 
    "a(b)" 
); 
static_assert(
    constructible<a>::from<c>::value, 
    "a(c)" 
); 
static_assert(
    constructible<a>::from<d>::value, 
    "a(d)" 
); 
Cuestiones relacionadas