5

I declared a C++ function declaration with 3 arguments, two of which had defaults like so.

void func(int const n, bool const flag=true, int *array=NULL) {
  /* print contents of array */
}

When I invoked the function erroneously, omitting the second argument but including the third argument, like so

int array[5]={1,2,3,4,5};
func(5,array);

neither gcc nor intel compilers (default ones on Ubuntu 14.04 LTS) complained that the last argument was specified without specifying the second last one. The code ran but sent in NULL for array (I expected the code to fail).

My question is why didn't the compilers complain that it could not find a matching function since the signature of my invocation should have appeared as

funct(int const, int *)

What options can I turn on during compiling to trigger a warning about this erroneous usage?

4
  • You should enable the "code reviewer yells at you for adding default arguments" warning :) Commented Mar 4, 2015 at 18:38
  • There's no warning that I know of. Array->pointer->bool is a perfectly well-defined conversion sequence. Commented Mar 4, 2015 at 18:42
  • This is a highly simplified but representative example constructed from a much more complex code where if I avoided arguments with default values, I would have so many overloaded functions for all the variants that it would be quite unwieldy. Commented Mar 4, 2015 at 21:00
  • Is there any mechanism to prevent an argument from undergoing implicit conversion. I am planning on using the method suggested by @Slava (i.e. to switch the order of arguments) but in the context of my larger code it would be semantically much clearer and cleaner, if I could keep the bool arguments with defaults before the pointer arguments with defaults and protect the pointer arguments from explicit conversion. Commented Mar 4, 2015 at 21:06

4 Answers 4

14

The compiler decays the array to a pointer and converts the pointer to a bool and proceeds.

Update

From the C++11 Standard:

4 Standard conversions [conv]

1 Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:

— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.

— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.

— Zero or one qualification conversion.

[ Note: A standard conversion sequence can be empty, i.e., it can consist of no conversions. —end note ]

A standard conversion sequence will be applied to an expression if necessary to convert it to a required destination type.

Sign up to request clarification or add additional context in comments.

14 Comments

This is why default arguments are so horrifying.
Is there 2 conversions array -> ponter -> bool ?
@Slava, that's my understanding.
@Slava: an array decays to a pointer so I'm not sure if that's consider that a conversion per se. Then the pointer can be converted to a bool.
@NathanOliver, Yes, array-to-pointer is a conversion per the standard. It's called, unimaginatively, an array-to-pointer conversion.
|
2

According to the C++ Standard (4 Standard conversions)

1 Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:

— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.

— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.

— Zero or one qualification conversion.

And

4.12 Boolean conversions

1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. For direct-initialization (8.5), a prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.

So this function call

func(5,array);

is equivalent to

func(5,array, NULL);

the second argument at first was converted from array to pointer (array-to-pointer conversion) and then was converted to boolean true (boolean conversions).

Thus this call is a valid call of the function. The compiler implicitly converts arguments to appropriate types.

Comments

2

There is an implicit casting to bool taking place. With Visual C++ you would get a C4800 warning. In gcc you can request specific warnings with options beginning with ‘-W’, for example -Wimplicit to request warnings on implicit declarations. See Options to Request or Suppress Warnings for the full documentation.

Comments

2

In this particular case solution could be using different argument order:

void func(int const n, int *array=NULL, bool const flag=true ) {
  /* print contents of array */
}

If you ommit second parameter boolean value cannot be implicitly converted to a pointer (unless you have bad habbit of using 0 as false), so it will fail to compile (or at least provide warning).

void func(int const n, int *array = nullptr, bool const flag=true ) {
      /* print contents of array */
}

int main()
{
    func( 0, false );
}

warning: converting 'false' to pointer type for argument 2 of 'void func(int, int*, bool)' [-Wconversion-null]

But in general it shows that you should use different technique. For example using std::vector instead of raw pointer.

typedef std::vector<int> int_vec;
void func( bool const flag=true, const int_vec &array = int_vec() ) {
      /* print contents of array */
}

int main()
{
    int_vec array {1,2,3,4,5};
    func( array );
}

error: cannot convert 'int_vec {aka std::vector}' to 'bool' for argument '1' to 'void func( bool, int_vec)'

1 Comment

If using 0 as a null pointer, you can at least get GCC to warn you that you should use nullptr.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.