James Raitsev
James Raitsev

Reputation: 96391

Why does C++ allow unnamed function parameters?

The following is a perfectly legal C++ code

void foo (int) {
    cout << "Yo!" << endl;
}

int main (int argc, char const *argv[]) {
    foo(5); 
    return 0;
}

I wonder, if there a value to ever leave unnamed parameters in functions, given the fact that they can't be referenced from within the function.

Why is this legal to begin with?

Upvotes: 56

Views: 27418

Answers (4)

egst
egst

Reputation: 1804

Just wanted to mention a specific (unusual but interesting) usecase - the "passkey idiom".

It uses a "dummy" parameter of a type, constructor of which is accessible only to its friends. Its purpose is only to check, whether the caller has access to this constructor. So it needs no name as it is not used in the function, only the compiler uses it.

It's used like this:

class Friendly; // Just a forward declaration

class Key {
private:
    Key() {}
    friend class Friendly;
};

class Safe() {
public:
    static int locked(Key, int i) {
        // Do something with `i`,
        // but the key is never used.
        return i;
    }
private:
    static void inaccessible() {}
};

class Friendly {
public:
    void foo() {
        int i = Safe::locked(Key(), 1); // OK
        int j = Safe::locked({}, 2);    // OK, sice C++11
    }
    void bar() {
        Safe::inaccessible(); // Not OK, its inaccessible
    }
};

int i = Safe::locked(3);        // Not OK, wrong parameters
int j = Safe::locked(Key(), 4); // Not OK, `Key` constructor is inaccessible
int k = Safe::locked({}, 5);    // Not OK, `{}` means `Key()` implicitly

Upvotes: 5

Merry Fitzpatrick
Merry Fitzpatrick

Reputation: 5

I just want to add that there is sometimes a difference whether you name a parameter or not. For example, the compiler treats a named rvalue reference as an lvalue and an unnamed rvalue reference as an rvalue.

// named-reference.cpp  
// Compile with: /EHsc  
#include <iostream>  
using namespace std;

// A class that contains a memory resource.  
class MemoryBlock  
{  
   // TODO: Add resources for the class here.  
};

void g(const MemoryBlock&)   
{  
   cout << "In g(const MemoryBlock&)." << endl;  
}

void g(MemoryBlock&&)   
{  
   cout << "In g(MemoryBlock&&)." << endl;  
}

MemoryBlock&& f(MemoryBlock&& block)  
{  
   g(block);  
   return block;  
}  

int main()  
{  
   g(f(MemoryBlock()));  
}  

This example produces the following output:

In g(const MemoryBlock&).
In g(MemoryBlock&&).

In this example, the main function passes an rvalue to f. The body of f treats its named parameter as an lvalue. The call from f to g binds the parameter to an lvalue reference (the first overloaded version of g).

Upvotes: -2

6502
6502

Reputation: 114481

Of course not naming a parameter is legal when just declaring the function, but it's also legal in the implementation. This last apparently strange version is useful when the function needs to declare the parameter to have a specific fixed signature, but the parameter is not needed.

This may happen for example for a method in a derived class, for a callback function or for a template parameter.

Not giving the parameter a name makes clear that the parameter is not needed and its value will not be used. Some compilers if you instead name a parameter and then simply don't use it will emit a warning that possibly there is a problem with the function body.

Upvotes: 15

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726539

Yes, this is legal. This is useful for implementations of virtuals from the base class in implementations that do not intend on using the corresponding parameter: you must declare the parameter to match the signature of the virtual function in the base class, but you are not planning to use it, so you do not specify the name.

The other common case is when you provide a callback to some library, and you must conform to a signature that the library has established (thanks, Aasmund Eldhuset for bringing this up).

There is also a special case for defining your own post-increment and post-decrement operators: they must have a signature with an int parameter, but that parameter is always unused. This convention is bordering on a hack in the language design, though.

Upvotes: 75

Related Questions