Выбрасывает std:: pair <T1, T2> const & to std:: pair <T1 const, T2> const & safe?

Безопасно (теоретически или на практике) reinterpret_cast a std::pair<T1, T2> const & в std::pair<T1 const, T2> const &, предполагая, что программист не намеренно сделал что-то странное, как специализирующееся std::pair<T1 const, T2>?

Ответы

Ответ 1

Это не переносимо для этого.

std::pair требования изложены в пункте 20.3. В пункте 17.5.2.3 разъясняется, что

В пунктах с 18 по 30 и в Приложении D не указывается представление классов и умышленно не указывается спецификация членов класса. Реализация может определять статические или нестатические члены класса или и то, и другое по мере необходимости для реализации семантики функций-членов, указанных в пунктах с 18 по 30 и в приложении D.

Это подразумевает, что он юридически (хотя и невероятно маловероятен) для реализации включает в себя частичную специализацию, такую ​​как:

template<typename T1, typename T2>
struct pair<T1, T2>
{
    T1 first;
    T2 second;
};

template<typename T1, typename T2>
struct pair<const T1, T2>
{
    T2 second;
    const T1 first;
};

которые явно не совместимы с макетами. Другие правила, включая включение дополнительных нестатических членов данных, возможно, до first и/или second также разрешены в соответствии с правилом.


Теперь несколько интереснее рассмотреть случай, когда макет известен. Хотя Potatoswatter указал на DR1334, который утверждает, что T и const T не совместимы с макетами, Стандарт предоставляет достаточные гарантии, чтобы позволить нам получить в любом случае:

template<typename T1, typename T2>
struct mypair<T1, T2>
{
    T1 first;
    T2 second;
};

mypair<int, double> pair1;
mypair<int, double>* p1 = &pair1;
int* p2 = reinterpret_cast<int*>(p1); // legal by 9.2p20
const int* p3 = p2;
mypair<const int, double>* p4 = reinterpret_cast<mypair<const int, double>*>(p3); // again 9.2p20

Однако это не работает на std::pair, поскольку мы не можем применить 9.2p20, не зная, что first на самом деле является исходным элементом, который не указан.

Ответ 2

pair определяется в разделе 20.3.2 стандарта, чтобы иметь данные:

template <class T1, class T2>
struct pair {
    T1 first;
    T2 second;
};

Это означает, что для конкретных типов T1, T2, pair<T1, T2> и pair<const T1, T2> гарантированы соответствующие члены данных:

struct pair<T1, T2> {
    T1 first;
    T2 second;
};
struct pair<const T1, T2> {
    const T1 first;
    T2 second;
};

Теперь, если T1 и T2 являются стандартными макетами, то pair<T1, T2> и pair<const T1, T2> являются стандартными макетами. Как обсуждалось выше, DR1334 они не совместимы с макетами (3.9p11), но на 9.2p19 они могут быть reinterpret_cast к их соответствующим T1 или const T1 первого члена. На 9.2p13 второй член T2 должен быть расположен после того, как первый член (то есть с более высоким адресом) и на 1.8p5 должен быть расположен сразу после первого элемента таким образом, чтобы объект был смежным после учета выравнивания (9.2p19).

Мы можем проверить это с помощью offsetof (который определен для типов стандартного макета):

static_assert(offsetof(pair<T1, T2>, second) ==
    offsetof(pair<const T1, T2>, second), "!");

Так как pair<T1, T2> и pair<const T1, T2> имеют один и тот же макет, кастинг в прямом направлении и использование результата для доступа к членам действительны по 3.9.2p3:

Если объект типа T расположен по адресу A, указатель типа cv T*, значение которого является адресом A, как говорят, указывает на этот объект, независимо от того, как это значение было Полученный.

Итак, reinterpret_cast безопасен, только если std::is_standard_layout<std::pair<T1, T2>>::value - true.

Ответ 3

Практический ответ заключается в том, что приведение в const должно быть безопасным, так как вы переводите текст на объект с идентичным представлением. Однако, наоборот, вводится поведение undefined (const неконстантно).

Что касается "теоретического" ответа, я должен отметить, что стандарт С++ не гарантирует идентичного поразрядного представления объектов const/non-const. Ключевое слово const гарантирует "концептуальную константу", которая зависит от реализации.