0

我知道下面的代码不起作用,我完全理解为什么。我实际上不明白的是为什么不

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")and a('b'),而且——我猜——编译器会使用类型名称对函数进行一次扩展,[T = const char*]然后使用[T = char].

这可能是一个简单的问题,即 C++ 做什么——以及它不做什么——,但我看不到如果执行扩展,是否有任何极端情况会出现错误。

4

3 回答 3

4

C++ 是一种已编译的静态类型语言,并且必须在编译时知道表达式的类型。表达式atoi(argv[1]) ? "foo" : 'b'可能是 aconst 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’
于 2013-04-07T13:32:10.997 回答
3

cout它与or无关operator <<。表达方式

atoi(argv[1]) ? "foo" : 'b'

本身不会编译。您输入的第二个和第三个运算符?:必须是相同的类型,或者可以隐式转换为彼此的类型。

于 2013-04-07T13:33:46.387 回答
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++ 来满足您的要求,但类型级联会无限增长。每次您有一个可以返回 typeA或 type的表达式时,都B必须对调用代码进行分叉,这可能会导致进一步的分叉。

必须扩展函数的签名以列出它“可能”返回的所有类型。

现在,虽然这可能是未来 C++ 的一个有价值的特性,但它不是 C++ 现在所做的。C++ 中的每个表达式都有一个单一的、明确的类型——在模板代码中,当您实例化模板时会发生这种情况。

顺便说一句,在 C++ 中具有多类型返回值的能力将为您提供类似于异常处理的能力,其中函数可以返回值或错误标志。由于调用代码必须在您调用多类型返回值函数时自动分叉,因此它必须处理该错误标志(通过将其作为替代类型返回,或通过本地处理)。

于 2013-04-07T13:38:50.297 回答