Syntactic Fructose
Syntactic Fructose

Reputation: 20076

Un-named function parameters

I'm looking at some code pertaining to the n3960 standard proposal and noticed some functions have parameters with no name, yet have a full function definition. Could someone explain how this is?

Example:

template <typename ExPolicy, typename IteratorTag>
void test_for_each(ExPolicy const& policy, IteratorTag) //just IteratorTag, no name?
{
    BOOST_STATIC_ASSERT(hpx::parallel::is_execution_policy<ExPolicy>::value);

    typedef std::vector<std::size_t>::iterator base_iterator;
    typedef test::test_iterator<base_iterator, IteratorTag> iterator;

    std::vector<std::size_t> c(10000);
    std::iota(boost::begin(c), boost::end(c), std::rand());

    hpx::parallel::for_each(policy,
        iterator(boost::begin(c)), iterator(boost::end(c)),
        [](std::size_t& v) {
            v = 42;
        });

    // verify values
    std::size_t count = 0;
    std::for_each(boost::begin(c), boost::end(c),
        [](std::size_t v) {
            HPX_TEST_EQ(v, std::size_t(42));
            ++count;
        });
    HPX_TEST_EQ(count, c.size());
}

Upvotes: 1

Views: 242

Answers (4)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

As noted, argument names are optional. But why was this omitted, and why have an argument without a name?

The technique being used here is function template tag type deduction based off of argument types.

You can call test_for_each passing in an instance of an arbitrary type as the 2nd parameter. Whatever the value type for that argument ends up being passed to the template function as IteratorTag.

Within the class, the value of the IteratorTag variable is not used -- all we care about is the type.

IteratorTags are used to distinguish between the various kinds of std library iterators -- forward, random access, input, output, etc.

With that type in hand, we can make subtle changes to how our code behaves (or less subtle, using overloading). In this case, the iterator type within the function takes the IteratorTag type as one of its template arguments, so the type of that variable differs based on the IteratorTag passed in.

Here is a simple version of this using the tag for a technique called "tag dispatching":

template<typename T>
int floor_to_int( T&& t, std::true_type ) { return std::forward<T>(t); }
template<typename T>
int floor_to_int( T&& t, std::false_type ) { return floor(std::forward<T>(t)); }
template<typename T>
int smart_floor( T&& t ) {
  return floor_to_int( std::forward<T>(t), std::is_integral< typename std::decay<T>::type >{} );
}

here the smart_floor function takes an arbitrary type T, and if and only if it is a non-integral type calls floor on it. Otherwise, it just converts it to an int.

We create an instance of the tag type -- in this case, std::is_integral< typename std::decay<T>::type > -- and pass it to an internal helper function. In this case, we have two overloads, neither of which uses the value of the passed in tag, just its type.

The above implementation is similar, except it has 1 overload for both cases. Maybe that tag type will be used deeper in in a similar overloading way, or maybe it is specialized in some traits class at some deeper level of use.

Odds are the argument here is supposed to be std::iterator_traits< T >::iterator_category or some homebrew boost variant, as an aside.

Upvotes: 6

R Sahu
R Sahu

Reputation: 206577

The argument name is left out in the following use cases, that I can think of:

  1. Virtual member functions. A derived class implementation may or may not need an argument. If it does not need the argument, the developer has the option to leave it out.

  2. To resolve an overload function based on just the type where the value of the argument is not useful.

Upvotes: 0

Baum mit Augen
Baum mit Augen

Reputation: 50053

If you do not actually need the value of the parameter, but must provide a certain interface, you can use an unnamed parameter. This is the correct way to silence the (important) unused parameter warning.

Upvotes: 3

isekaijin
isekaijin

Reputation: 19742

In a function prototype, argument names are optional. They might be useful as documentation, but they are not used by the compiler in any meaningful way.

In a function definition, if an argument is not used in the function's body, its name is again optional:

Foo some_function(Bar bar, Baz)
{
    // this is the body of a function that
    // does not use its second argument
}

Upvotes: 1

Related Questions