我知道以下代码不起作用,我完全理解为什么。我实际上不明白的是为什么不:
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*]
的函数进行一次扩展,而另一个使用{{ 1}}。
这可能是一个简单的问题C ++的作用 - 以及它没有做什么 - 但是我没有看到是否有任何角落案例如果执行扩展会出现错误。
答案 0 :(得分:4)
C ++是一种编译的静态类型语言,表达式的类型必须在编译时知道。表达式atoi(argv[1]) ? "foo" : 'b'
可以是const char*
或char
,具体取决于argv[1]
的值,这在编译时无法知道。只有在程序实际执行时才知道该值。因此,当编译器试图将此表达式转换为机器代码时,它无法决定将表达式视为哪种类型。
要看到它与operator<<
没有任何关系,只需单独使用表达式:
int main(int argc, const char* argv[])
{
atoi(argv[1]) ? "foo" : 'b';
}
即使是此won't compile,也会出现以下错误:
error: operands to ?: have different types ‘const char*’ and ‘char’
答案 1 :(得分:3)
它与cout
或operator <<
无关。表达式
atoi(argv[1]) ? "foo" : 'b'
本身不会编译。您向?:
提供的第二个和第三个运算符必须是相同的类型,或者可以隐式转换为另一个的类型。
答案 2 :(得分:1)
这是您认为应该要求的:
#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 ++中使用多类型返回值的能力将为您提供类似于异常处理的功能,其中函数可以返回值或错误标志。由于调用代码必须在调用多类型返回值函数时自动分叉,因此它必须处理该错误标志(通过将其作为替代类型返回,或通过在本地处理它)。