C : cout с конечным if-оператором

#c #if-statement #cout

#c #if-оператор #cout

Вопрос:

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

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

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

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

1. Почему не просто if (i%5==0) cout << endl; ?

2. Потому что он хочет использовать тернарный оператор.

3. @kalyan: Напрашивается вопрос. «Как я могу сделать X?» » Почему X?» «Потому что я хочу X». Не отвечает на вопрос: Зачем здесь использовать условное выражение? Это уродливо, чрезмерно сложно и никогда на самом деле не будет работать.

4. @Tony: Добавление "" в cout не имеет никакого существенного эффекта, так зачем это вообще делать в этом случае ?

5. @Tony: Какое отношение к этому имеют другие случаи? Я говорю, что это использование уродливо и чрезмерно сложно. Рассмотрим это выражение в стихах Георга: что легче читать?

Ответ №1:

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

Первая проблема заключается в том, что 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 . Исходное сообщение об ошибке, которое вы получали, исчезнет.

Однако это немедленно выявит вторую, более серьезную проблему с этим выражением: specialized 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
  

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

1. 1 И если бы он был явно выбран, то он все равно потерпел бы неудачу, потому что указатель на функцию и строковый литерал не имеют ничего общего.

2. охватывает много вопросов, на которые мне не хватало терпения. 1.

Ответ №2:

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

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

 expr ? "n" : ""
  

… соответствует вашим потребностям — он похож, но не очищает поток (ИМХО, std::cout обычно его следует очищать как можно реже — особенно низкоуровневым библиотечным кодом — поскольку это обеспечивает лучшую производительность). (Это также более гибко, например, expr ? "whatevern" : "" / не может добавляться endl к строковому литералу.)

Например, для GCC 4.5.2 endl является:

 template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>amp; 
    endl(basic_ostream<_CharT, _Traits>amp; __os)
    { return flush(__os.put(__os.widen('n'))); }
  

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

1. Я проголосовал против AndreyT за его объяснения, но 1 за то, что фактически предоставил решение 🙂

Ответ №3:

  • Две альтернативы ?: должны иметь один и тот же тип, иначе одна из них может быть преобразована в другую.

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

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

Ответ №4:

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

 cout << "";
  

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

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

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

 if (1) { doSomething(); }
  

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

Ответ №5:

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

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

Ответ №6:

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

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

Ответ №7:

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

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

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

1. Вы пробовали это сами? Будет ли он компилироваться?

2. Время оглянуться на старые вещи?