Вопрос

I know the following code does not work, and I fully understand why. What I actually do not understand is why not:

int main(int argc, char *argv[]) {
    std::cout << (atoi(argv[1]) ? "foo" : 'b') << std::end;
}

Why: Of course, this expression may generate either a string or an integer, and this is the error pointed by the compiler:

error: operands to ?: have different types ‘const char*’ and ‘char’

Why not: Since the operator<< have a bind with both of the types const char* and char, why is it the compiler don't perform a code expansion as in a template -- which, I guess, is what is performed.

For example, if I had:

template <class T>
void a(const T& value) {
    std::cout << a << std::endl;
}

I could call either a("foo") and a('b'), and -- I guess -- the compiler would do one expansion of the function with the type name [T = const char*] and another one with [T = char].

This may be a simple matter of what C++ does -- and what it does not --, but I fail to see if there's any corner case that would come up as an error if the expansion was performed.

Это было полезно?

Решение 2

It has nothing to do with cout or operator <<. The expression

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

itself wouldn't compile. The 2nd and 3rd operators that you feed to ?: must be either the same type, or types that are implicitly convertible to one other.

Другие советы

C++ is a compiled statically-typed language and the type of an expression must be known at compile-time. The expression atoi(argv[1]) ? "foo" : 'b' could be a const char* or char, depending on the value of argv[1], which can't be known at compile-time. It's only when the program is actually executed that this value is known. So when the compiler is attempting to turn this expression into machine code, it can't decide which type to treat the expression as.

To see that it really doesn't have anything to do with the operator<<, just have the expression by itself:

int main(int argc, const char* argv[])
{
  atoi(argv[1]) ? "foo" : 'b';
}

Even this won't compile, giving the following error:

error: operands to ?: have different types ‘const char*’ and ‘char’

This is what you think you should be asking for:

#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;
}

but it isn't what ? does.

C++ could be modified to do what you are asking, but the type cascade would grow boundlessly. Each time you have an expression that could return type A or type B, the calling code would have to be forked, which could cause further forking.

Signatures of functions would have to be expanded to list all of the types it "could" return.

Now, while this may be a worthwhile feature for C++ in the future, it isn't what C++ does now. Each expression in C++ has a single, definite type -- in template code, this occurs when you have instantiated the template.

As an aside, the ability to have poly-type return values in C++ would give you capabilities similar to exception handling, where a function could return a value or an error flag. As the calling code would have to automatically fork whenever you call a poly-type return value function, it would have to handle that error flag (either by returning it as an alternative type, or by handling it locally).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top