Приведение к целочисленному типу или другому типу не может отображаться в постоянном выражении

#c

#c

Вопрос:

Ideone testcase: http://ideone.com/lzepF

Код:

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

#include <stdint.h>

template <typename T> std::ostreamamp; write(std::ostreamamp; os, T constamp; x);
template <typename T> std::istreamamp; read(std::istreamamp; is, Tamp; x);

template <typename T, typename U> std::ostreamamp; write(std::ostreamamp; os, std::pair<T, U> constamp; rh);
template <typename T, typename U> std::istreamamp; read(std::istreamamp; is, std::pair<T, U>amp; rh);

template <typename T> std::ostreamamp; writeContainer(std::ostreamamp; os, T constamp; rh);

template <typename T, typename U> std::ostreamamp; write(std::ostreamamp; os, std::map<T, U> constamp; rh);
template <typename T, typename U> std::istreamamp; read(std::istreamamp; is, std::map<T, U> rh);

template <typename T> std::ostreamamp; write(std::ostreamamp; os, std::vector<T> constamp; rh);
template <typename T> std::istreamamp; read(std::istreamamp; is, std::vector<T>amp; rh);

template <typename T>
std::ostreamamp; write(std::ostreamamp; os, T constamp; 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 *>(amp;x), sizeof(T));
    return os;
}

template <typename T>
std::istreamamp; read(std::istreamamp; is, Tamp; 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 *>(amp;x), sizeof(T));
    return is;
}

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

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

template <typename T>
std::ostreamamp; writeContainer(std::ostreamamp; os, T constamp; 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::istreamamp; readContainer(std::istreamamp; is, Tamp; 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::ostreamamp; write(std::ostreamamp; os, std::map<T, U> constamp; rh){
    return writeContainer(os, rh);
}

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

template <typename T>
std::ostreamamp; write(std::ostreamamp; os, std::vector<T> constamp; rh){
    return writeContainer(os, rh);
}

template <typename T>
std::istreamamp; read(std::istreamamp; is, std::vector<T>amp; 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;
}
  

Ошибки:

 prog.cpp: In function 'std::ostreamamp; write(std::ostreamamp;, const Tamp;) [with T = unsigned int, std::ostream = std::basic_ostream<char>]':
prog.cpp:57:2:   instantiated from 'std::ostreamamp; writeContainer(std::ostreamamp;, const Tamp;) [with T = std::vector<int>, std::ostream = std::basic_ostream<char>]'
prog.cpp:92:30:   instantiated from 'std::ostreamamp; write(std::ostreamamp;, const std::vector<T>amp;) [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::ostreamamp; write(std::ostreamamp;, const Tamp;) [with T = int, std::ostream = std::basic_ostream<char>]':
prog.cpp:60:3:   instantiated from 'std::ostreamamp; writeContainer(std::ostreamamp;, const Tamp;) [with T = std::vector<int>, std::ostream = std::basic_ostream<char>]'
prog.cpp:92:30:   instantiated from 'std::ostreamamp; write(std::ostreamamp;, const std::vector<T>amp;) [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
  

Поскольку у нас нет номеров строк, 🙁 , он жалуется на ПЕРВОЕ write(s, x) и, как мне кажется, жалуется на reinterpret_cast<const char*>(const unsigned int*) , но я уверен, что это должно быть законно.

Что происходит не так?

Комментарии:

1. Вместо std::is_pointer<T>() etc., не так ли std::is_pointer<T>::value ?

Ответ №1:

Вы is_pod is_pointer неправильно используете и . Вам необходимо изменить его на следующее:

     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");
  

Вы можете протестировать с помощью этого:

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

Ответ №2:

C 03 Стандарт 5.19 «Константные выражения», пункт 1 гласит:

В нескольких местах C требует выражений, которые вычисляются до целочисленной или перечисляемой константы: как границы массива (8.3.4, 5.3.4), как выражения регистра (6.4.2), как длины битовых полей (9.6), как инициализаторы перечислителя (7.2), как инициализаторы статических элементов (9.4.2) и как целыеили перечисление нетиповых аргументов шаблона (14.3).

constant-expression: условное выражение

Целочисленное константное выражение может включать в себя только литералы (2.13), перечислители, переменные const или статические элементы данных целочисленных или перечисляемых типов, инициализированные константными выражениями (8.5), нетиповые шаблонные параметры целочисленных или перечисляемых типов и выражения sizeof. Плавающие литералы (2.13.3) могут появляться, только если они приведены к целочисленным или перечислительным типам. Можно использовать только преобразования типов в целочисленные или перечисляемые типы.В частности, за исключением выражений sizeof, не должны использоваться функции, объекты класса, указатели или ссылки, а также не должны использоваться операторы присваивания, увеличения, уменьшения, вызова функции или запятой.

Операторы кода:

static_assert(!std::is_pointer(), «Это указатель, вы, вероятно, не хотите его записывать»); static_assert(std::is_pod(), «Это не POD: не могу его записать»);

нарушите это правило, и, следовательно, компилятор пожалуется.

Комментарии:

1. Это все еще верно для C 11? OP сообщает об успешном выполнении исходного кода в более новой g версии .

2. @Tomalakgeret’kal: Позвольте мне посмотреть черновик C 11 и получить ответ.

3. @Tomalakgeret’kal: Да, это изменено в C 11, стандарт больше не налагает этого ограничения, кажется, gcc был достаточно быстрым, чтобы соответствовать C 11.