Самый портативный и надежный способ получить адрес переменной в С++

Использование & для получения адреса переменной может быть проблематичным, если тип переменной перегружен operator&(). Например, _ com_ptr_ имеет operator&() перегружен побочным эффектом изменения объекта.

Теперь у меня есть сложный набор шаблонов с такими функциями:

template<class T>
void process( const T* object )
{
    //whatever
}    

template<class T>
void tryProcess( T& object )
{
    process( &object )
}

В tryProcess() мне нужно получить указатель T*, содержащий адрес фактического объекта типа T.

Вышеупомянутая реализация tryProcess() будет работать только в том случае, если class T не имеет перегруженного operator&(). Поэтому, если я вызываю tryProcess<_com_ptr_<Interface>>(), я могу получить неожиданные результаты - срабатывает перегруженный operator&().

В другом вопросе следующее обходное решение :

template<class T>
T* getAddress( T& object )
{
   return reinterpret_cast<T*>( &reinterpret_cast<char&>( object ) );
}

С такой функцией я могу реализовать tryProcess() следующим образом:

template<class T>
void tryProcess( T& object )
{
    process( getAddress( object ) )
}

и всегда будет получать одно и то же поведение независимо от того, перегружен ли class T operator&(). Это вводит нулевые накладные расходы с оптимизацией на Visual С++ 7 - компилятор получает то, что нужно делать, и просто получает адрес объекта.

Насколько переносимым и стандартным компилятором является это решение проблемы? Как это можно улучшить?

Ответ 1

Это стандартная жалоба. Этот вопрос был доведен до сведения комитета ISO С++ в отношении проблем с реализациями offsetof, которые нарушили это. Среди рассмотренных решений были ужесточение определения POD или добавление дополнительного ограничения на типы, которые будут использоваться с offsetof. Эти решения были отклонены, когда решение reinterpret_cast было поднято. Поскольку это предлагало стандартный способ устранения проблемы, комитет не видел необходимости добавлять дополнительные требования к offsetof и оставил исправления для реализаций.

Ответ 2

Boost addressof реализуется с помощью трюка reinterpret_cast, поэтому я бы сказал, что он, вероятно, переносимый и стандартно-совместимый.

Здесь вы можете увидеть код, о котором идет речь.