resueltos - Manera elegante de prevenir el envenenamiento del espacio de nombres en C++
ejercicios resueltos de cadenas en c++ (1)
Supongamos que Bob ha envuelto su biblioteca en el espacio de nombres "bob", y Alicia va a hacer que todo el espacio de nombres sea visible dentro de su propia función mediante un solo "uso de espacio de nombres bob", en lugar de "usar bob :: XYZ" para cada uno ít:
// This file is written by Alice:
#include <iostream>
// She uses Bobs library:
#include "bob.hpp"
int main(void) {
// Import Bobs library and use it:
using namespace bob;
unsigned short value = 50000;
bob::dump_as_signed(value);
// Should not be possible without std:: prefix:
cout << "foobar" << endl;
}
Por otro lado, Bob trató de evitar dichos escenarios al incluir la implementación dentro de un espacio de nombres ficticio, y al hacer que solo estos símbolos estén disponibles, que están destinados a otros usuarios:
// This file is written by Bob
#include <iostream>
#include <type_traits>
// Namespace for public use:
namespace bob {
// Implementation details:
namespace impl_ {
// Visible ONLY within sub-namespace:
using std::cout;
using std::endl;
using std::is_integral;
using std::make_signed;
// No repeated std:: prefixes at all:
template <typename T,
typename S = typename make_signed<T>::type>
void dump_as_signed(const T i) {
static_assert(is_integral<T>::value, "no integer");
// Do something very very useful:
cout << "signed:" << static_cast<S>(i) << endl;
}
}
// Make available without poisoning with std::*:
using impl_::dump_as_signed;
}
Debido a que todas las directivas de uso se envuelven en un espacio de nombres "impl_" ficticio dentro del espacio de nombres principal de Bobs, no hay riesgo de que Alice importe accidentalmente símbolos del espacio de nombres std :: también.
Entonces, mis preguntas son:
- No me gusta que haya un espacio de nombres ficticio para los detalles de implementación, que es "teóricamente" visible para todos. ¿Hay alguna manera más agradable de poder utilizar muchos símbolos de, por ejemplo, std :: sin fugas de estos Y sin prefijar cada símbolo explícito con std ::? (También estoy pensando en los API-Doc generados, que muestran "bob :: impl _ :: XYZ" en lugar de "bob :: XYZ").
- Creo que no es muy seco repetir std :: aso una y otra vez en todas partes. También entiendo que un "uso de espacio de nombres estándar" relativamente global dentro de un ámbito más amplio (como una clase) no es tan hermoso, pero cientos de prefijos std :: son mucho más feos, en mi opinión. Además de los problemas de envenenamiento: ¿Cuál crees que es más agradable y por qué? ¿O tienes una idea completamente diferente?
OK, espero que mi pregunta sea clara. ¡Gracias por leer! :)
Supongamos que Alice está usando dos bibliotecas, hechas por Bob y Charlie .
// This file is written by Alice:
#include <bob.hpp>
#include <charlie.hpp>
int main(void) {
using namespace bob;
using namespace charlie;
// Do a bunch of stuff
}
Ahora, Charlie inventa una nueva característica llamada foobar
que agrega a su biblioteca. foobar
es genial y a sus usuarios les gusta. Alice comienza a usarlo también.
Luego Bob dice: "También me gusta foobar
, quiero tener mi propio foobar
que pueda usar en mi biblioteca. Pero no quiero depender de Charlie". Entonces él crea su propia versión.
Uh oh, ahora el código de Alice no compila! Cada uso de foobar
en el código de Alice es ambiguo y ella tiene que reescribir todo su proyecto.
Entonces, lo mismo sucederá el próximo mes. Y el próximo mes después de eso.
Ahora, todos los clientes de Alice están realmente descontentos porque están creando grandes tecnologías y tratando de mantener versiones actualizadas de sus dependencias, pero cada vez que intentan actualizar algo, el código de Alice se rompe. Hacen muchos informes de errores en su rastreador de errores.
Alice envía un correo electrónico a Bob y Charlie y dice
Chicos, tienen que dejar de hacer clases con los mismos nombres, o voy a perder todo mi negocio!
Bob y Charlie le envían un correo electrónico a Alice:
Sin Alice, debes dejar de
using namespace bob;
yusing namespace charlie;
en tu código Eso no es compatible con Bob o Charlie.
Ahora, volvamos a contar la misma historia, excepto que no hay Charlie. Es solo que Alice hace sus propias clases en su proyecto, colisionando con nuevos nombres agregados por Bob.
En resumen, using namespace
una directiva de using namespace
nunca es una buena idea (en mi opinión). Especialmente cuando el espacio de nombres es una biblioteca externa. Realmente no sabes cómo ese espacio de nombres puede cambiar en el futuro, y si cambia de una manera que es mala para ti, de repente tienes un gran lío en tus manos.
Usar namespace =
para acortar espacios de nombres suele ser una muy buena idea. Me gusta hacer lo siguiente:
namespace my_lib {
namespace qi = boost::spirit::qi;
// Do stuff with qi
// ...
} // end namespace my_lib
De esa forma, puedo usar el nombre corto qi
en my_lib
, pero no my_lib
nada a mis usuarios. (¿Quién espero que no esté using namespace my_lib;
)
Si eres un usuario, podrías hacer algo como
namespace cha = charlie::name::space::is_way_too_long;
Sin embargo, debería estar más que feliz de escribir espacios de nombres cortos como bob::
o std::
, ya sea que usted sea un usuario o un implementador de la biblioteca, si esto significa que su código no se romperá cuando las bibliotecas se actualicen.
Esto no es sobre SECO. Poner algún tipo de calificador en los nombres hace que sea mucho más fácil leer su código y entender lo que significa.
Por ejemplo, mira SDL, una biblioteca C popular. Que yo sepa, cada macro en SDL comienza SDL_
y cada función comienza sdl_
. ¿Es eso una violación de "DRY"? No. Aquí no hay detalles de implementación duplicados: el prefijo común está ahí para evitar colisiones de nombres. Además, hace que el código sea más legible y mantenible, cada vez que veo un símbolo que está hablando de una entidad SDL que conozco tan inmediatamente. Es muy útil tanto para los humanos como para las computadoras.
Poniendo using namespace std;
o using namespace my_lib;
es como tomar una de las mejores características de C ++ y arrojarla a la basura. La desventaja es, ahórrese escribiendo 5 caracteres, a costa de hacer un gran daño a la legibilidad y mantenibilidad.
Pensamiento de despedida: ¿Cómo afecta el using namespace
a la calidad de los mensajes de error que recibe?
Aquí hay un programa simple que no compila:
#include <iostream>
struct foo {};
int main() {
std::cout << foo{} << std::endl;
}
Cuando el compilador vea este código, tendrá que probar cada sobrecarga de operador de ruta que conoce y comprobar si foo
es convertible a cualquiera de esas cosas. Como std::cout
es uno de los argumentos, ADL significa que tenemos que buscar todo el std
nombres std
. Resulta, sorpresa sorpresa, foo
no es convertible a ninguna de esas cosas. En gcc 5.3
recibo el siguiente mensaje de error (200 líneas).
main.cpp: In function ‘int main()’:
main.cpp:6:13: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘foo’)
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = foo] <near match>
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
/usr/include/c++/5/ostream:628:5: note: conversion of argument 1 would be ill-formed:
main.cpp:6:20: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(__ostream_type& (*__pf)(__ostream_type&))
^
/usr/include/c++/5/ostream:108:7: note: no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}’
/usr/include/c++/5/ostream:117:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
operator<<(__ios_type& (*__pf)(__ios_type&))
^
/usr/include/c++/5/ostream:117:7: note: no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}’
/usr/include/c++/5/ostream:127:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(ios_base& (*__pf) (ios_base&))
^
/usr/include/c++/5/ostream:127:7: note: no known conversion for argument 1 from ‘foo’ to ‘std::ios_base& (*)(std::ios_base&)’
/usr/include/c++/5/ostream:166:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(long __n)
^
/usr/include/c++/5/ostream:166:7: note: no known conversion for argument 1 from ‘foo’ to ‘long int’
/usr/include/c++/5/ostream:170:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned long __n)
^
/usr/include/c++/5/ostream:170:7: note: no known conversion for argument 1 from ‘foo’ to ‘long unsigned int’
/usr/include/c++/5/ostream:174:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(bool __n)
^
/usr/include/c++/5/ostream:174:7: note: no known conversion for argument 1 from ‘foo’ to ‘bool’
In file included from /usr/include/c++/5/ostream:638:0,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:91:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]
basic_ostream<_CharT, _Traits>::
^
/usr/include/c++/5/bits/ostream.tcc:91:5: note: no known conversion for argument 1 from ‘foo’ to ‘short int’
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:181:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned short __n)
^
/usr/include/c++/5/ostream:181:7: note: no known conversion for argument 1 from ‘foo’ to ‘short unsigned int’
In file included from /usr/include/c++/5/ostream:638:0,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:105:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]
basic_ostream<_CharT, _Traits>::
^
/usr/include/c++/5/bits/ostream.tcc:105:5: note: no known conversion for argument 1 from ‘foo’ to ‘int’
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:192:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned int __n)
^
/usr/include/c++/5/ostream:192:7: note: no known conversion for argument 1 from ‘foo’ to ‘unsigned int’
/usr/include/c++/5/ostream:201:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(long long __n)
^
/usr/include/c++/5/ostream:201:7: note: no known conversion for argument 1 from ‘foo’ to ‘long long int’
/usr/include/c++/5/ostream:205:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned long long __n)
^
/usr/include/c++/5/ostream:205:7: note: no known conversion for argument 1 from ‘foo’ to ‘long long unsigned int’
/usr/include/c++/5/ostream:220:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(double __f)
^
/usr/include/c++/5/ostream:220:7: note: no known conversion for argument 1 from ‘foo’ to ‘double’
/usr/include/c++/5/ostream:224:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(float __f)
^
/usr/include/c++/5/ostream:224:7: note: no known conversion for argument 1 from ‘foo’ to ‘float’
/usr/include/c++/5/ostream:232:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(long double __f)
^
/usr/include/c++/5/ostream:232:7: note: no known conversion for argument 1 from ‘foo’ to ‘long double’
/usr/include/c++/5/ostream:245:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(const void* __p)
^
/usr/include/c++/5/ostream:245:7: note: no known conversion for argument 1 from ‘foo’ to ‘const void*’
In file included from /usr/include/c++/5/ostream:638:0,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:119:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
basic_ostream<_CharT, _Traits>::
^
/usr/include/c++/5/bits/ostream.tcc:119:5: note: no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}’
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:574:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*)
operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
^
/usr/include/c++/5/ostream:574:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘const unsigned char*’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:569:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)
operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
^
/usr/include/c++/5/ostream:569:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘const signed char*’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:556:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*)
operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
^
/usr/include/c++/5/ostream:556:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘const char*’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/ostream:638:0,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:321:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*)
operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
^
/usr/include/c++/5/bits/ostream.tcc:321:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘const char*’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:539:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*)
operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
^
/usr/include/c++/5/ostream:539:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: mismatched types ‘const _CharT*’ and ‘foo’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:519:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char)
operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
^
/usr/include/c++/5/ostream:519:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘unsigned char’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:514:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char)
operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
^
/usr/include/c++/5/ostream:514:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘signed char’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:508:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char)
operator<<(basic_ostream<char, _Traits>& __out, char __c)
^
/usr/include/c++/5/ostream:508:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘char’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:502:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char)
operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
^
/usr/include/c++/5/ostream:502:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘char’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from main.cpp:1:
/usr/include/c++/5/ostream:497:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT)
operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
^
/usr/include/c++/5/ostream:497:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: deduced conflicting types for parameter ‘_CharT’ (‘char’ and ‘foo’)
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/bits/ios_base.h:46:0,
from /usr/include/c++/5/ios:42,
from /usr/include/c++/5/ostream:38,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/system_error:209:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::error_code&)
operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e)
^
/usr/include/c++/5/system_error:209:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: cannot convert ‘foo{}’ (type ‘foo’) to type ‘const std::error_code&’
std::cout << foo{} << std::endl;
^
In file included from /usr/include/c++/5/string:52:0,
from /usr/include/c++/5/bits/locale_classes.h:40,
from /usr/include/c++/5/bits/ios_base.h:41,
from /usr/include/c++/5/ios:42,
from /usr/include/c++/5/ostream:38,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:5172:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/usr/include/c++/5/bits/basic_string.h:5172:5: note: template argument deduction/substitution failed:
main.cpp:6:20: note: ‘foo’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’
std::cout << foo{} << std::endl;
^
Este es el punto: si lo haces using namespace bob;
, ¡entonces todos los tipos de bob
que son transmisibles también aparecerán en esa lista! Si lo haces using namespace charlie;
¡entonces todos sus tipos estarán allí también!
No solo los mensajes de error serán peores, hay una mayor probabilidad de que pueda obtener una interacción realmente extraña que no esperaba. ¿Qué pasa si los tipos de Bob son ocasionalmente transmisibles a uno de los tipos de Charlie? ¿Y los tipos de Charlie ocasionalmente son convertibles a algún tipo estándar que sea transmisible?
Y, por supuesto, todo esto se aplica no solo a cualquier sobrecarga del operador, sino a cualquier plantilla o llamada de función.
Entonces, en conclusión, C ++ es mucho más fácil de razonar y funciona mucho mejor si evitas mezclar mucha basura en un espacio de nombres.