Я знаю следующий код не работает, и я полностью понимаю Зачем. Что я на самом деле не понимаю, так это почему бы и нет:
int main(int argc, char *argv[]) {
std::cout << (atoi(argv[1]) ? "foo" : 'b') << std::end;
}
ЗачемКонечно, это выражение может генерировать либо строку, либо целое число, и это ошибка, указанная компилятором:
error: operands to ?: have different types ‘const char*’ and ‘char’
Почему бы и нет: С operator<<
иметь связь с обоими типами const char*
а также char
почему компилятор не выполняет расширение кода, как в шаблоне — что, я думаю, и выполняется.
Например, если бы я имел:
template <class T>
void a(const T& value) {
std::cout << a << std::endl;
}
Я мог бы позвонить либо a("foo")
а также a('b')
и — я полагаю — компилятор сделает одно расширение функции с именем типа [T = const char*]
и еще один с [T = char]
,
Это может быть простой вопрос о том, что делает C ++, а что нет, но я не вижу, есть ли какой-нибудь угловой случай, который выглядел бы как ошибка, если бы расширение было выполнено.
Это не имеет ничего общего с cout
или же operator <<
, Выражение
atoi(argv[1]) ? "foo" : 'b'
сам не скомпилирует. 2-й и 3-й операторы, которым вы кормите ?:
должен быть либо того же типа, либо типов, которые неявно преобразуются друг в друга.
C ++ — это скомпилированный статически типизированный язык и тип выражения должен быть известен во время компиляции. Выражение atoi(argv[1]) ? "foo" : 'b'
может быть const char*
или же char
в зависимости от стоимости argv[1]
, который не может быть известен во время компиляции. Только когда программа действительно выполняется, это значение известно. Поэтому, когда компилятор пытается превратить это выражение в машинный код, он не может решить, к какому типу обращаться с выражением.
Чтобы увидеть, что это на самом деле не имеет ничего общего с operator<<
Просто имейте выражение:
int main(int argc, const char* argv[])
{
atoi(argv[1]) ? "foo" : 'b';
}
Даже это не скомпилируется, дает следующую ошибку:
error: operands to ?: have different types ‘const char*’ and ‘char’
Это то, что вы думаете, вы должны просить:
#include <iostream>
#include <utility>
#include <type_traits>
#include <functional>
template<typename Left, typename Right>
auto tri( bool b, Left&& left, Right&& right )
-> decltype( std::forward<Left>(left)() )
{
if (b)
return std::forward<Left>(left)();
else
return std::forward<Right>(right)();
}
int main(int /*argc*/, char *argv[]) {
tri(
atoi(argv[1]),
[]()->std::ostream&{ return std::cout<<"foo"; },
[]()->std::ostream&{ return std::cout<<'b'; }
) << std::endl;
}
но это не то, что ?
делает.
C ++ может быть изменен, чтобы делать то, что вы просите, но каскад типов будет расти безгранично. Каждый раз, когда у вас есть выражение, которое может вернуть тип A
или введите B
код вызова должен быть разветвлен, что может привести к дальнейшему разветвлению.
Сигнатуры функций должны быть расширены, чтобы перечислить все типы, которые он «мог» возвращать.
Теперь, хотя в будущем это может быть полезным для C ++, это не то, что сейчас делает C ++. Каждое выражение в C ++ имеет один определенный тип — в коде шаблона, это происходит, когда вы создаете экземпляр шаблона.
Кроме того, возможность иметь поли-тип возвращаемых значений в C ++ даст вам возможности, аналогичные обработке исключений, где функция может возвращать значение или флаг ошибки. Поскольку вызывающий код должен будет автоматически разветвляться всякий раз, когда вы вызываете функцию возвращаемого значения поли-типа, он должен обрабатывать этот флаг ошибки (либо возвращая его как альтернативный тип, либо обрабатывая его локально).