Как я могу решить этот адрес перегруженной функции-члена? - PullRequest
0 голосов
/ 28 июля 2010

[ РЕДАКТИРОВАТЬ - Я давно забыл, что это было здесь, пока я не получил 2500 просмотров "заметный вопрос".Поскольку люди просматривают - в принятом ответе есть полезная информация о перегрузках, но конкретная проверка на std::endl еще хуже, чем я предполагал в то время, и, безусловно, неправильная вещь.

По сути, эффект отstd::endl - для вывода \n в поток, затем сбрасывание с std::flush.Это независимо от платформы, включая Windows, где конец строки действительно "\ r \ n".Манипулятор endl не абстрагируется от различий между платформами и заканчивается строкой WRT, C ++ обрабатывает так же, как это делает C - переводя \n в "\ r \ n" (для текстового режима, а не двоичного) позже.Я думал, что C ++ делает что-то другое, такое сильное предположение, что я никогда не сомневался в этом в течение двух десятилетий, но я ошибался.

Я не помню деталей, но в любом случае возможно определить ваши собственные потоки, иобеспечить альтернативный вывод (и перевод) любых символов, в которые идет поток. Все манипуляторы должны работать должным образом, за до ваш пользовательский код потока увидит получающиеся выходные символы.Таким образом, чтобы обеспечить особое поведение конца строки, следите за \n там (который все еще находится перед переводом конца строки в текстовом файле).]

Это хакерское дело, я знаю, но недавно мне нужно было реализовать класс потока, который бы действовал в основном как стандартный поток, но который обнаруживал бы манипулятор std :: endl и в особом случае это поведение.Моя первая попытка реализации конкретного метода была ...

mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&))
{
  if (p == &std::endl)
  {
    //  Handle special case
  }
  else
  {
    m_Underlying_Stream << p;
  }

  return *this;
}

Проблема в том, что компилятор не знает, на какую перегрузку std::endl я имею в виду.Я решил это следующим образом ...

mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&))
{
  typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&);

  const ENDL_T l_ENDL (&std::endl);

  if (p == l_ENDL)
  {
    //  Handle special case
  }
  else
  {
    m_Underlying_Stream << p;
  }

  return *this;
}

То есть компилятор может разрешить перегрузку в контексте инициализации (и для присваивания, как доказал другой эксперимент), но не для operator==.

Рассматриваемый компилятор - MinGW GCC 4.4.0, но я не думаю, что это может быть проблемой компилятора.

Я осмотрелся и нашел этот вопрос ...

Как получить адрес перегруженной функции-члена?

Если в моем коде есть проблема с константой, я не знаю, куда нужно перейти отсутствующей константой.Я не вижу никаких других очевидных проблем с типами.

У меня есть смутные представления о проблемах с числом шагов, перегрузке WRT или неявном приведении, но ничего конкретного.Итак, может ли кто-нибудь четко объяснить, что не так с моим первым примером, почему вторая версия исправляет это, и как я могу безопасно указать, какую перегрузку я имею в виду, принимая адрес функции.

Кстати: я могу догадатьсянекоторым людям не понравится, когда я тестирую адрес std::endl, и они укажут, что это хрупко - например, у кого-то может быть свой собственный манипулятор, который вызывает std::endl, который я бы не заметилВ общем, это правда, но в этом особом случае взлом экономит много времени, а злобность просто не имеет значения.

Ответы [ 3 ]

2 голосов
/ 28 июля 2010

Использование имени перегруженной функции (или имени шаблона функции, который ведет себя как набор перегруженных функций) без аргументов (например, в выражении "address of") разрешено только в ограниченном наборе контекстов где контекст может использоваться для однозначного определения требуемой конкретной перегрузки.

Это указано в 13.4 стандарта (ISO / IEC 14882: 2003) [over.over]. Включены инициализатор для объекта или ссылки или в явном преобразовании. Это дает вам несколько вариантов.

например. явное преобразование:

typedef std::ostream& (*ManipPtr)(std::ostream&);

mystream& mystream::operator<<(ManipPtr p)
{
    if (p == static_cast<ManipPtr>(&std::endl))
    {
        // ...

Непосредственная инициализация указателя:

typedef std::ostream& (*ManipPtr)(std::ostream&);

mystream& mystream::operator<<(ManipPtr p)
{
    const ManipPtr pEndl = &std::endl;

    if (p == pEndl)
    {
        // ...
1 голос
/ 28 июля 2010

работают следующие работы:

#include <iostream>

struct mystream {
    typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&);
    mystream& operator<< (ENDL_T p)
    {
        if (p == (ENDL_T)std::endl)
        {
            std::cout << "special case\n";
        }
        else
        {
            std::cout << "usual case\n";
        }
        return *this;
    }
};

int main()
{
    mystream ms;
    ms << std::endl; // prints "special case"
    ms << std::flush; // prints "usual case"
}
0 голосов
/ 28 июля 2010

Причина, по которой он не может отличить перегрузки, заключается в том, что вы определяете адрес функции, а не вызываете ее. Когда вы вставляете его в поток, компилятор знает, что нужно вызвать перегрузку endl(ostream&). Кроме этого, ты сам по себе.

Почему бы просто не проверить вместо этого \ n?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...