unidades tipos tipo sirve reglas programa para operador este dev datos dato convertir conversión conversiones conversion binario c++ function casting implicit-conversion implicit-cast

c++ - sirve - reglas para la conversión de tipos casting



¿Cómo evito las conversiones implícitas en funciones que no son de construcción? (7)

¿Cómo evito la conversión implícita en funciones que no son de construcción?
Tengo una función que toma un entero como parámetro,
pero esa función también tomará caracteres, bools y longs.
Creo que lo hace echándolos implícitamente.
¿Cómo puedo evitar esto para que la función solo acepte parámetros de un tipo coincidente y rechace la compilación de lo contrario?
Hay una palabra clave "explícito" pero no funciona en funciones que no son de construcción. : /
¿qué debo hacer?

El siguiente programa compila, aunque me gustaría que no:

#include <cstdlib> //the function signature requires an int void function(int i); int main(){ int i{5}; function(i); //<- this is acceptable char c{''a''}; function(c); //<- I would NOT like this to compile return EXIT_SUCCESS; } void function(int i){return;}

* Asegúrese de señalar cualquier uso indebido de la terminología y los supuestos


Aquí hay una solución general que causa un error en tiempo de compilación si se llama a la function con cualquier cosa menos un int

template <typename T> struct is_int { static const bool value = false; }; template <> struct is_int<int> { static const bool value = true; }; template <typename T> void function(T i) { static_assert(is_int<T>::value, "argument is not int"); return; } int main() { int i = 5; char c = ''a''; function(i); //function(c); return 0; }

Funciona al permitir que funcione cualquier tipo de argumento, pero usar is_int como un predicado de nivel de tipo. La implementación genérica de is_int tiene un valor falso, pero la especialización explícita para el tipo int tiene un valor verdadero, de modo que la afirmación estática garantiza que el argumento tiene exactamente el tipo int contrario hay un error de compilación.


Bueno, iba a responder esto con el siguiente código, pero a pesar de que funciona con Visual C ++, en el sentido de producir el error de compilación deseado, MinGW g ++ 4.7.1 lo acepta, ¡e invoca el constructor de referencia rvalue!

Creo que debe ser un error de compilación, pero podría estar equivocado, entonces, ¿alguien?

De todos modos, aquí está el código, que puede resultar ser una solución compatible con el estándar (o, ¡puede resultar que sea un thinko de mi parte!):

#include <iostream> #include <utility> // std::is_same, std::enable_if using namespace std; template< class Type > struct Boxed { Type value; template< class Arg > Boxed( Arg const& v, typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0 ) : value( v ) { wcout << "Generic!" << endl; } Boxed( Type&& v ): value( move( v ) ) { wcout << "Rvalue!" << endl; } }; void function( Boxed< int > v ) {} int main() { int i = 5; function( i ); //<- this is acceptable char c = ''a''; function( c ); //<- I would NOT like this to compile }


Defina la función de plantilla que coincida con todos los demás tipos:

void function(int); // this will be selected for int only template <class T> void function(T) = delete; // C++11

Esto se debe a que las funciones que no son de plantilla con coincidencia directa siempre se consideran primero. Luego, se considera la función de plantilla con coincidencia directa, por lo que nunca se usará la function<int> . Pero para cualquier otra cosa, como char, se usará la function<char> , y esto le da a su compilación errores:

void function(int) {} template <class T> void function(T) = delete; // C++11 int main() { function(1); function(char(1)); // line 12 }

ERRORES:

prog.cpp: In function ''int main()'': prog.cpp:4:6: error: deleted function ''void function(T) [with T = char]'' prog.cpp:12:20: error: used here

Esta es la forma de C ++ 03:

// because this ugly code will give you compilation error for all other types class DeleteOverload { private: DeleteOverload(void*); }; template <class T> void function(T a, DeleteOverload = 0); void function(int a) {}


No se puede directamente, porque un char se promueve automáticamente a int .

Sin embargo, puede recurrir a un truco: cree una función que tome un char como parámetro y no lo implemente. Se compilará, pero obtendrá un error de vinculador:

void function(int i) { } void function(char i); //or, in C++11 void function(char i) = delete;

Llamar a la función con un parámetro char interrumpirá la construcción.

Ver http://ideone.com/2SRdM

Terminología: ¿funciones no constructivas? ¿Te refieres a una función que no es un constructor?


Para C ++ 14 (y creo que C ++ 11), puede deshabilitar los constructores de copia mediante la sobrecarga de rvalue-references también:

Ejemplo: supongamos que tiene una clase de Binding<C> base Binding<C> , donde C es la clase de Constraint base o una clase heredada. Supongamos que está almacenando el Binding<C> por valor en un vector, y pasa una referencia al enlace y desea asegurarse de no causar una copia implícita.

Puede hacerlo eliminando func(Binding<C>&& x) (según el ejemplo de PiotrNycz) para casos específicos de valor de referencia.

Retazo:

template<typename T> void overload_info(const T& x) { cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl; } template<typename T> void overload_info(T&& x) { cout << "overload: " << name_trait<T>::name() << "&&" << endl; } template<typename T> void disable_implicit_copy(T&& x) = delete; template<typename T> void disable_implicit_copy(const T& x) { cout << "[valid] "; overload_info<T>(x); } ... int main() { Constraint c; LinearConstraint lc(1); Binding<Constraint> bc(&c, {}); Binding<LinearConstraint> blc(&lc, {}); CALL(overload_info<Binding<Constraint>>(bc)); CALL(overload_info<Binding<LinearConstraint>>(blc)); CALL(overload_info<Binding<Constraint>>(blc)); CALL(disable_implicit_copy<Binding<Constraint>>(bc)); // // Causes desired error // CALL(disable_implicit_copy<Binding<Constraint>>(blc)); }

Salida:

>>> overload_info(bc) overload: T&& >>> overload_info<Binding<Constraint>>(bc) overload: const Binding<Constraint>& >>> overload_info<Binding<LinearConstraint>>(blc) overload: const Binding<LinearConstraint>& >>> overload_info<Binding<Constraint>>(blc) implicit copy: Binding<LinearConstraint> -> Binding<Constraint> overload: Binding<Constraint>&& >>> disable_implicit_copy<Binding<Constraint>>(bc) [valid] overload: const Binding<Constraint>&

Error (con clang-3.9 en bazel , cuando la línea ofensiva está sin comentar):

cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function ''disable_implicit_copy'' CALL(disable_implicit_copy<Binding<Constraint>>(blc)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Código fuente completo: prevent_implicit_conversion.cc


Primero probé el enfoque de PiotrNycz (para C ++ 03, que estoy obligado a usar para un proyecto), luego traté de encontrar un enfoque más general y encontré esta clase de plantilla ForcedType<T> .

template <typename T> struct ForcedType { ForcedType(T v): m_v(v) {} operator T&() { return m_v; } operator const T&() const { return m_v; } private: template <typename T2> ForcedType(T2); T m_v; }; template <typename T> struct ForcedType<const T&> { ForcedType(const T& v): m_v(v) {} operator const T&() const { return m_v; } private: template <typename T2> ForcedType(const T2&); const T& m_v; }; template <typename T> struct ForcedType<T&> { ForcedType(T& v): m_v(v) {} operator T&() { return m_v; } operator const T&() const { return m_v; } private: template <typename T2> ForcedType(T2&); T& m_v; };

Si no me equivoco, esas tres especializaciones deberían cubrir todos los casos de uso comunes. No estoy seguro de si realmente se necesita una especialización para rvalue-reference (en C ++ 11 en adelante) o si el valor es suficiente.

Uno lo usaría así, en el caso de una función con 3 parámetros cuyo tercer parámetro no permita conversiones implícitas:

function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);


Quizás puedas usar una estructura para hacer que la segunda función sea privada:

#include <cstdlib> struct NoCast { static void function(int i); private: static void function(char c); }; int main(){ int i(5); NoCast::function(i); //<- this is acceptable char c(''a''); NoCast::function(c); //<- Error return EXIT_SUCCESS; } void NoCast::function(int i){return;}

Esto no compilará:

prog.cpp: In function ‘int main()’: prog.cpp:7: error: ‘static void NoCast::function(char)’ is private prog.cpp:16: error: within this context