2011-10-04 11 views
5

Ideone caso_prueba: http://ideone.com/lzepFmoldeada de tipo integral o de otro tipo no puede aparecer en una expresión constante

Código:

#include <iostream> 
#include <sstream> 
#include <vector> 
#include <map> 
#include <list> 
#include <set> 

#include <stdint.h> 

template <typename T> std::ostream& write(std::ostream& os, T const& x); 
template <typename T> std::istream& read(std::istream& is, T& x); 

template <typename T, typename U> std::ostream& write(std::ostream& os, std::pair<T, U> const& rh); 
template <typename T, typename U> std::istream& read(std::istream& is, std::pair<T, U>& rh); 

template <typename T> std::ostream& writeContainer(std::ostream& os, T const& rh); 

template <typename T, typename U> std::ostream& write(std::ostream& os, std::map<T, U> const& rh); 
template <typename T, typename U> std::istream& read(std::istream& is, std::map<T, U> rh); 

template <typename T> std::ostream& write(std::ostream& os, std::vector<T> const& rh); 
template <typename T> std::istream& read(std::istream& is, std::vector<T>& rh); 

template <typename T> 
std::ostream& write(std::ostream& os, T const& x){ 
    static_assert(!std::is_pointer<T>(), "That's a pointer, you probably don't want to write that"); 
    static_assert(std::is_pod<T>(), "That's not a POD: can't write it"); 
    os.write(reinterpret_cast<const char *>(&x), sizeof(T)); 
    return os; 
} 

template <typename T> 
std::istream& read(std::istream& is, T& x){ 
    static_assert(!std::is_pointer<T>(), "That's a pointer, you probably don't want to read that"); 
    static_assert(std::is_pod<T>(), "That's not a POD: can't read it"); 
    is.read(reinterpret_cast<char *>(&x), sizeof(T)); 
    return is; 
} 

template <typename T, typename U> 
std::ostream& write(std::ostream& os, std::pair<T, U> const& rh){ 
    write(os, rh.first); 
    write(os, rh.second); 
    return os; 
} 

template <typename T, typename U> 
std::istream& read(std::istream& is, std::pair<T, U>& rh){ 
    read(is, rh.first); 
    read(is, rh.second); 
    return is; 
} 

template <typename T> 
std::ostream& writeContainer(std::ostream& os, T const& rh){ 
    uint32_t size = std::distance(rh.begin(), rh.end()); 
    write(os, size); 

    for(auto it = rh.begin(); it != rh.end(); ++it){ 
     write(os, *it); 
    } 

    return os; 
} 

template <typename T> 
std::istream& readContainer(std::istream& is, T& rh){ 
    uint32_t size; 
    read(is, size); 
    std::insert_iterator<T> it(rh, rh.end()); 

    for(uint32_t i=0; i<size; ++i) { 
     typename T::value_type x; 
     read(is, x); 
     it = x; 
    } 
    return is; 
} 

template <typename T, typename U> 
std::ostream& write(std::ostream& os, std::map<T, U> const& rh){ 
    return writeContainer(os, rh); 
} 

template <typename T, typename U> 
std::istream& read(std::istream& is, std::map<T, U> rh){ 
    return readContainer(is, rh); 
} 

template <typename T> 
std::ostream& write(std::ostream& os, std::vector<T> const& rh){ 
    return writeContainer(os, rh); 
} 

template <typename T> 
std::istream& read(std::istream& is, std::vector<T>& rh){ 
    return readContainer(is, rh); 
} 

int main(){ 
    { 
     std::stringstream s; 
     std::vector<int> x = {0, 1, 2, 3}; 
     write(s, x); 
    } 

    { 
     std::stringstream s; 
     std::map<int, int> x = {{0, 0}, {1, 2}, {2, 4}, {3, 6}}; 
     write(s, x); 
    } 

    return 0; 
} 

Errores:

prog.cpp: In function 'std::ostream& write(std::ostream&, const T&) [with T = unsigned int, std::ostream = std::basic_ostream<char>]': 
prog.cpp:57:2: instantiated from 'std::ostream& writeContainer(std::ostream&, const T&) [with T = std::vector<int>, std::ostream = std::basic_ostream<char>]' 
prog.cpp:92:30: instantiated from 'std::ostream& write(std::ostream&, const std::vector<T>&) [with T = int, std::ostream = std::basic_ostream<char>]' 
prog.cpp:104:13: instantiated from here 
prog.cpp:29:11: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression 
prog.cpp:29:11: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression 
prog.cpp: In function 'std::ostream& write(std::ostream&, const T&) [with T = int, std::ostream = std::basic_ostream<char>]': 
prog.cpp:60:3: instantiated from 'std::ostream& writeContainer(std::ostream&, const T&) [with T = std::vector<int>, std::ostream = std::basic_ostream<char>]' 
prog.cpp:92:30: instantiated from 'std::ostream& write(std::ostream&, const std::vector<T>&) [with T = int, std::ostream = std::basic_ostream<char>]' 
prog.cpp:104:13: instantiated from here 
prog.cpp:29:11: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression 
prog.cpp:29:11: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression 

ya que no tenemos los números de línea,: (, se queja sobre el PRIMERO write(s, x), y me parece que me quejo del reinterpret_cast<const char*>(const unsigned int*) pero estoy bastante seguro de que debería ser legal.

¿Qué está pasando?

+1

En lugar de 'std :: is_pointer ()' etc., ¿no debería ser 'std :: is_pointer :: value'? –

Respuesta

5

Está utilizando el is_pod y is_pointer incorrectamente. Es necesario cambiar a la siguiente:

static_assert(!std::is_pointer<T>::value, "That's a pointer, you probably don't want to write that"); 
    static_assert(std::is_pod<T>::value, "That's not a POD: can't write it"); 

Puede probar con esto:

write(std::cout, 1); 
    int *p = 0; 
    write(std::cout, p); 
+0

Los números de línea están ligeramente apagados, entonces? Odio cuando eso sucede ... –

+0

@ TomalakGeret'kal, sí, está un poco jodido ... – Nim

+0

Es curioso, también funciona para() en gcc-4.6.1 .. Extraño. ¡Gracias! – Nick

1

C++ 03 estándar 5.19 "Las expresiones constantes", párrafo 1 estados:

En varios lugares, C++ requiere expresiones que evalúen una constante integral o de enumeración: como límites de matriz (8.3.4, 5.3.4), como expresiones de caso (6.4.2), como longitudes de campo de bit (9.6), como enumerador i nitializadores (7.2), como inicializadores de miembros estáticos (9.4.2), y como argumentos de plantillas de tipo no integrales o de enumeración (14.3).

constante-expresión: condicional-expresión

Una integral constante-expresión puede implicar sólo literales (2.13), enumeradores, variables const o miembros de datos estáticos de tipos integrales o de enumeración inicializados con expresiones constantes (8,5) , parámetros de plantilla sin tipo de tipo integral o de enumeración, y tamaño de expresiones. Los literales flotantes (2.13.3) solo pueden aparecer si se convierten a tipos integrales o de enumeración. Solo se pueden usar conversiones de tipos a tipos integrales o de enumeración. En particular, excepto en el tamaño de las expresiones, no se usarán funciones, objetos de clase, punteros o referencias, y no se usarán los operadores de asignación, incremento, decremento, llamada de función o coma.

Las instrucciones de código:

static_assert (std :: is_pointer(), "que es un puntero, es probable que no quiero escribir que"!); static_assert (std :: is_pod(), "Eso no es un POD: no puede escribirlo");

rompan esta regla y por lo tanto el compilador se queja.

+0

¿Sigue siendo cierto para C++ 11? OP reporta el éxito con el código original en el nuevo 'g ++'. –

+0

@ TomalakGeret'kal: Déjame buscar C++ 11 draft y getback. –

+0

@ TomalakGeret'kal: Sí, esto se cambió en C++ 11, El estándar ya no impone esta restricción, Parece que gcc ha sido lo suficientemente rápido para cumplir con el C++ 11. –

Cuestiones relacionadas