从比较中扩展类型

时间:2013-04-07 13:29:04

标签: c++ templates compiler-construction typing

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

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 ++的作用 - 以及它没有做什么 - 但是我没有看到是否有任何角落案例如果执行扩展会出现错误。

3 个答案:

答案 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)

它与coutoperator <<无关。表达式

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 ++中使用多类型返回值的能力将为您提供类似于异常处理的功能,其中函数可以返回值或错误标志。由于调用代码必须在调用多类型返回值函数时自动分叉,因此它必须处理该错误标志(通过将其作为替代类型返回,或通过在本地处理它)。