C ++: cout с тернарным оператором if - PullRequest
9 голосов
/ 20 апреля 2011

Я получаю эту ОШИБКУ: «ошибка: перегруженная функция без контекстной информации о типе».

cout << (i % 5 == 0) ? endl : "";

Возможно ли то, что я делаю; я просто делаю это неправильно или мне нужно перегрузить оператор <<? </p>

Ответы [ 7 ]

31 голосов
/ 20 апреля 2011

Это не сработает (даже если вы исправите ошибку приоритета). У вас здесь две проблемы, вторая более серьезная, чем первая.

Первая проблема заключается в том, что std::endl - это шаблон. Это шаблон функции. Шаблон должен быть специализированным. Чтобы специализировать этот шаблон, компилятор должен знать (выводить) аргументы шаблона. Когда вы делаете

std::cout << std::endl;

конкретный тип указателя на функцию, ожидаемый operator <<, - это то, что компилятор использует, чтобы выяснить, как специализировать шаблон std::endl.

Однако в вашем примере вы по существу «отсоединили» std::endl от operator <<, переместив std::endl в подвыражение ?:. Теперь компилятор должен сначала скомпилировать это выражение

(i % 5 == 0) ? endl : ""

Это выражение не может быть скомпилировано, так как компилятор не знает, как специализировать шаблон std::endl. Нет никакого способа вывести аргументы шаблона без какого-либо контекста.

Например, эта простая программа на C ++

#include <iostream>
int main() {
   std::endl;
}

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

Вы можете «помочь» компилятору решить проблему, указав аргументы шаблона явно

(i % 5 == 0) ? endl<char, char_traits<char> > : "";

Это явно скажет компилятору, как создать экземпляр endl. Исходное сообщение об ошибке, которое вы получили, исчезнет.

Однако это сразу же выявит вторую, более серьезную проблему с этим выражением: специализированная endl - это функция (которая в этом контексте распадается на указатель функции), а "" - строковый литерал. Вы не можете смешивать указатель функции и строковый литерал в таком операторе ?:. Эти типы несовместимы. Они не могут использоваться вместе как 2-й и 3-й операнд троичного ?:. Об этой второй проблеме компилятор выдаст другое сообщение об ошибке.

Итак, в общем, последняя проблема, с которой вы столкнулись, выглядит так, как будто вы пытались сделать что-то вроде

cout << (i % 5 == 0 ? 10 : "Hi!");

Это не скомпилируется по той же причине, по которой ваше выражение не скомпилируется.

Итак, выражение, которое вы пытаетесь написать, не может быть написано таким образом. Перепишите его, не пытаясь использовать оператор ?:.


В качестве поддержки смотрите следующую расшифровку:

$ cat qq.cpp
#include <iostream>
using namespace std;
int main (void) {
    int i = 5;
    cout << ((i % 5 == 0) ? endl : "");
    return 0;
}

$ g++ -o qq qq.cpp
qq.cpp: In function 'int main()':
qq.cpp:5: error: overloaded function with no contextual type information
15 голосов
/ 20 апреля 2011

Два аргумента оператора ? должны быть одного типа (по крайней мере, после включения потенциальных продвижений, неявных конструкторов, операторов приведения и т. Д.). std::endl на самом деле является шаблоном функции (подробности ниже), который затем вызывается потоком для воздействия на его состояние: это не строковый литерал, такой как "".

Итак, вы не можете сделать это точно , но вы, вероятно, можете получить поведение, которое вам действительно нужно - подумайте, ...

expr ? "\n" : ""

... соответствует вашим потребностям - он аналогичен, но не очищает поток (IMHO, std::cout обычно следует сбрасывать как можно реже - особенно с помощью низкоуровневого кода библиотеки - поскольку это обеспечивает лучшую производительность). (Он также более гибкий, например, expr ? "whatever\n" : "" / не может добавить endl к строковому литералу.)

например. для GCC 4.5.2 endl:

template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>& 
    endl(basic_ostream<_CharT, _Traits>& __os)
    { return flush(__os.put(__os.widen('\n'))); }
3 голосов
/ 20 апреля 2011
  • Две альтернативы ?: должны иметь одинаковый тип или быть конвертируемыми в другой.

  • endl - это шаблон, и контекст не дает достаточно информации для выбора. Так что это даже не тип. (Это ваше сообщение об ошибке).

  • Как уже говорили другие, привязка не та, которую вы ожидаете.

2 голосов
/ 20 января 2017

Попробуйте, все работает:

cout << ((i % 5 == 0) ? "\n" : "");
2 голосов
/ 20 апреля 2011

Это вполне возможно (я сам в этом сомневаюсь). Тем не менее, это также глупо, так же эффективно, как:

cout << "";

Что вы должны делать в этом случае, просто:

if (i % 5 == 0) cout << endl;

Вы не должны использовать троичный только для того, чтобы использовать его. На самом деле вы не должны использовать любую языковую функцию только ради ее использования. Я не пишу код вроде:

if (1) { doSomething(); }

только потому, что я могу. Простой doSomething(); намного лучше.

1 голос
/ 13 сентября 2017

Вот как это должно выглядеть для правильной работы:

cout << ((i % 5 == 0) ? '\n' : " ");
0 голосов
/ 20 апреля 2011

Оператор << имеет более высокий приоритет, чем ?:.Попробуйте это:

cout << ((i % 5 == 0) ? endl : "");
...