What is the recommended way to pass "empty" types as parameters? By
empty I mean that they have no fields (or methods, typically), thus
really serving as placeholders (e.g. mpl::void_, null_type or even
none_t.)
Is it better to accept them as values, const values or const
references? E.g.
void foo(void_);
void foo(void_ const);
void foo(void_ const&);
By "better" I mean in terms of both semantics (making it clear to
readers that it's a placeholder) and optimization (since I'm not sure
which one is usually easier for a smart compiler to eliminate
entirely.)
Thanks.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
It probably depends on the use-context and what one would
consider as "empty" parameter. Empty parameters are obviously
often used for tagging-based overload selection or as positional
indicators like std::placeholders::_1.
So any decision about that depends on this concrete use-case
and I don't think that it can be reasonably answered without
being aware of this context. Your concrete example that attempts
to fake a void parameter by introducing a fake-tag type seems
unconvincing to me if presented without context. In C++0x you
could realize this with an enforced empty parameter pack, if you
really want, like so:
template<class... T,
class = typename std::enable_if<sizeof...(T) == 0>::type>
void foo(T&&...);
but the question is, what the reason is for introducing such a
seemingly artificial parameter.
HTH & Greetings from Bremen,
Daniel Krügler
[..]
After rereading, it seems that I have completely misunderstood
the OP's question, don't ask me, why.
To hopefully properly respond to the original question: I have never
seen a different parameter form than "by value" for empty types.
It is IMO the most appropriate form, because there is no single
indirection involved. I don't know of any architecture, where
this approach would not be at least as effective as providing such
parameters by reference.
In regard to the "semantics" part of the question: I also have
never seen any problems on that side due to "by value"
approach. The reason might be that typically such placeholders
have unproblematic names, like.
In your particular example, an out-of-context declaration of
void foo(void_);
looks indeed irritating, but I don't think that this is a real
world, problem, is it?
Usually, such meta-programming tag types are part of a
dedicated namespace, so I would expect to read here
something like
void foo(mpl::void_);
to solve such a problem, if at all. Syntax-highlighting of
keywords of todays compiler IDE's or editors also reduce
the risk for misunderstanding the semantics. In other words:
I doubt that using reference parameters instead of
non-reference parameters solve the actual problem (if there
is one).
Last but not least: Your particular example looks still
very odd to me (as expressed in my first reply). I cannot
remember where I have see something like void_ in a
*function* parameter list. It typically occurs in template
parameter lists, where such usage is even less a problem.
HTH & Greetings from Bremen,
Daniel Kr=FCgler
Oh, the example was totally contrived. The real situations in which I
need to do this are more complicated as they involve heavy template
meta-programming; I'm not sure I can reduce those to something
meaningful but concise. Well, there's two other situations that I can
think of that might qualify:
1) I might need to be able to print (or more specifically, "skip")
this empty value, e.g. because it can form part of a compound type
such as a tuple<>. Thus I'll need an operator << for it. E.g.:
std::ostream& operator <<(std::ostream& o, void_ const&) { return o; =
}
2) I have a function that returns its parameter (so, more or less the
identity function), except when the parameter is "empty," in which
case I need a different default-constructed type. So, something like:
template <typename T>
T const& t_or_default(T const& t) { return t; }
result_type t_or_default(void_ const&) { return result_type(); }
Thus my question stands: what's the best way to accept those empty types?
> In C++0x you
> could realize this with an enforced empty parameter pack, if you
> really want, like so:
>
> template<class... T,
> class = typename std::enable_if<sizeof...(T) == 0>::type>
> void foo(T&&...);
>
> but the question is, what the reason is for introducing such a
> seemingly artificial parameter.
Ah, neat. Thanks!
First, I would really *not* name this parameter "_void" - IMO
this leads to similar confusion like i versus l, plus the
semantic confusion. I think that names like "empty" or "none"
are better here, but of-course this is only my personal
preference.
Second: Yes, I agree that such use-cases make sense and I
really don't see any reason for *not* using by-value call
convention here.
> 2) I have a function that returns its parameter (so, more or less the
> identity function), except when the parameter is "empty," in which
> case I need a different default-constructed type. So, something like:
>
> template <typename T>
> T const& t_or_default(T const& t) { return t; }
> result_type t_or_default(void_ const&) { return result_type(); }
>
> Thus my question stands: what's the best way to accept those empty types?
I would provide them by value, it's probably the most
reasonable calling convention for empty (or "small")
types, unless you have to satisfy other restricting
constraints, e.g. when specializing a function template
which already uses a function parameter/return type
that is a reference type as in the following variant:
template<>
const void_& t_or_default(void_ const& arg) { return arg; }
HTH & Greetings from Bremen,
Daniel Kr=FCgler