50

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?

Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58
James Raitsev
  • 92,517
  • 154
  • 335
  • 470
  • The only place I've ever seen it actually used is for prototypes; I've seen some function prototypes and class definitions that omitted the parameter names for brevity or other reasons. I'm not sure why it's legal. – Wug Aug 29 '12 at 21:25
  • 3
    One standard use case is in [Tag Dispatching](http://www.generic-programming.org/languages/cpp/techniques.php#tag_dispatching) – Edvard Fagerholm Jul 14 '15 at 11:10
  • I used dummy parameters in one of my designs where I have an object with two sets of identically typed members. The constructor usually only initializes one set of members. My factory method knows which set to be initialized. To distinguish the two different sets, I used a dummy bool parameter for the second set. For illustration: class Twosets { private: int leftA; char leftB; int rightA; char rightB; public: Twosets(int a, char b); Twosets(int a, charb, bool); The later will be used to construct the right members. – Kemin Zhou Jun 17 '20 at 03:17

4 Answers4

67

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.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    ...or for regular functions that are to be used as a callback (and therefore must conform to a given signature) but don't need to use the parameter. – Aasmund Eldhuset Aug 29 '12 at 21:25
  • @AasmundEldhuset, True, I usually name those unused parameters `unused`, though, to make it clearer. – chris Aug 29 '12 at 21:27
  • 1
    Can't unused parameters also be used for function overloading purposes? – Lily Ballard Aug 29 '12 at 21:34
  • 1
    @KevinBallard Arguably, this is how the pre-increment vs. post-increment convention is using it. I think that using otherwise unused parameters for overloads is somewhat of a hack, though: overloads are resolved at compile time, so there is no reason not to use a distinct name rather than adding an unused parameter. – Sergey Kalinichenko Aug 29 '12 at 21:37
  • 2
    @dasblinkenlight: Good point about post-increment, but the type of the unnamed parameter can be used as well. This is actually (ab)used in STL for template parameters in various implementations. This sort of trick is mainly useful for template functions/classes, so you can change which function you're invoking based on traits of the template parameter types. – Lily Ballard Aug 29 '12 at 21:41
  • @KevinBallard You are right, templates are a different story altogether: their programming model borders on Prolog's unification, giving the number and the type of parameters a whole new meaning. You're right about the "abuse", though - there's a lot of "write-only" code in the standard C library. – Sergey Kalinichenko Aug 29 '12 at 21:45
  • 10
    Worth mentioning that some compilers can warn about unused parameters: Making them unnamed will fix the warning. – Roddy Aug 29 '12 at 22:39
  • @chris That's less clear to me. Giving unused args dummy names is pointless, pollutes the scope with identifiers you don't want to - but now accidentally _can_ - use, generates warnings for any decent set of compiler flags, and I imagine is really tedious especially if you have >1. In contrast, not giving such arguments a name is a standard way to express that you don't care about them, don't want to reserve names for them, and don't require warnings about them. How is `unused` clearer? – underscore_d May 20 '17 at 11:57
  • @underscore_d, Honestly, I don't even remember 5 years ago. Nowadays, if you really want to name it, you can attach `[[maybe_unused]]`, and the only advantage I see is being able to name the parameter according to what it is actually for so that you know what you're not using, while having the attribute to be explicit about not using it. – chris May 21 '17 at 06:21
  • The rationale about callbacks is also applicable to C, but there omission of parameter name (other than in a prototype) is not allowed. – Ruslan Jul 09 '19 at 11:14
  • I’ve just read similar examples in Nikolai M. Josuttis’es book “The c++ standard library”. He uses std::true_type and std::false_type as a disambiguation between overloads (page 153) – IC_ Jul 27 '20 at 04:50
15

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.

6502
  • 112,025
  • 15
  • 165
  • 265
3

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
egst
  • 1,605
  • 3
  • 18
  • 25
-2

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).

  • This is logical, setting a name to a variable basically means "I'm gonna use it in the following statements", thus, lvalue. Specifying whether it's lvalue or rvalue doesn't depend on it's origin, but whether the reference in memory will persist after the statement. – Imad Nabil Alnatsheh May 01 '17 at 22:41
  • 1
    This is unrelated. The question is about unnamed arguments, those lacking identifiers on the receiving function's side. You're talking about the value category passed from the caller's side - while incidentally including unnamed arguments, but not in a relevant way. Any difference here is because of the passed value category, not the presence or absence of a name for the argument. Because you don't forward/move the rvalue reference in the first, inner call to `g()`, the `const&` overload must win. The fact you need a name in order to forward it is completely incidental. – underscore_d May 20 '17 at 12:06
  • This isn't even valid code (`return block;` should fail to compile). VTD, is irrelevant to the question. – M.M Oct 23 '18 at 02:31