Default argument promotion in functions - c++

I'm trying to see default argument promotion in functions. Specifically I want to test section 6.5.2.2 Function calls (described here).
I want to have a prototype-less function call to see default argument promotion to integer but I get "Function does not take 1 arguments" error. This is what I'm trying to do:
#include<iostream>
using namespace std;
//void Func(char val);
//void Func(int val);
void Func(); // No prototype
int main(int argc, char** argv)
{
char charVal = 'a';
cout << "Func(charVal) - "; Func(charVal);
return 0;
}
void Func(char val)
{
cout << "Char arg. Result: " << val << endl;
}
void Func(int val)
{
cout << "Int arg. Result: " << val << endl;
}
I expected to see Func(int) being called due to argument promotion.
Is this removed from the standard already?
Cheers.
P.S- I just saw that this kind of prototype-less declarations are part of C standard, NOT C++. Any particular reason why C++ doesn't support it?

All functions (and named entities in general) need to be declared before use. You've only declared the overload with no parameters (which is what an empty parameter list means in C++) when you try to call it with an argument in main.
You have the correct declarations at the start of the file, but for some reason the one you need is commented out. Uncomment them and it's fine.
I just saw that this kind of prototype-less declarations are part of C standard, NOT C++. Any particular reason why C++ doesn't support it?
Because C++ supports overloading. Overload resolution happens at compile time, where the function is called, and candidates can only be considered if the compiler knows they exist - that is, if they've been fully declared so that the compiler can match their signatures against the argument types of the function call.
In C, the compiler knows which function you mean, whether or not it knows the parameter types, since it's the only one with that name. Such declarations are merely dangerous, removing type-checking from the argument types and opening the door to all manner of bugs.

C++ has never supported prototype-less function declarations. The empty argument list in C++ means no arguments, not a lack of prototype.
The reason is that C++ has type-safe linking, and that just doesn't work if you don't have a prototype. And C++ has type-safe linking because that's just a good idea and reduces bugs. (You can read Design&Evolution of C++ for more details.)
Argument promotions in C++ exist only in calls to true variadic functions, i.e. those declared with a ... in the argument list.

Related

Function with 0 arguments - void vs void*?

I know that you can declare a function without any arguments simply like this:
void test()
{
cout << "Hello world!!" << endl;
}
But I have also seen
void test(void)
{
cout << "Hello world!!" << endl;
}
and
void test(void*)
{
cout << "Hello world!!" << endl;
}
My question is: What is the difference between using void and void* here?
The one an only form for a function with no parameters in C++ should be
void test();
The form:
void test(void)
That is how you define a function with no parameters in c. But in C++ use this form only for interfacing with c:
extern "C"
{
void test(void);
}
This form:
void test(void*)
Is not a function with no arguments. It has an argument of type void* that is unnamed. It expects a void* pointer when called.
Have a look here for an explanation of what a void* pointer is: What does void* mean and how to use it?
What is the difference between using void and void* here?
When the argument type is void, the function must be called without any arguments.
When the argument type is void*, the function must be called with an argument that is a void* or can be converted to a void*.
void stands for "nothing" but void* does not stand for "pointer to nothing". In fact, it's quite the contrary. void* stands for pointer to anything except void. It is oxymoronic but that's how the language defines those two.
My question is: What is the difference between using void and void* here?
(void) parameter list is same as empty parameter list. The void here does nothing in C++ and is unnecessary unless compatibility with C is needed - see the second part of the answer.
(void*) does not accept 0 arguments. It accepts 1 argument. The type of the parameter is void* which is a pointer type.
Why is it like this?
Because of backwards compatibility with C. In C, (void) is the only way to declare a function that only accepts empty argument list. () parameter list declares any function without specifying the parameters. The number of parameters could be any, including 0. The use of () parameter list in C is becoming an obsolete feature.
Quote from C11 standard draft N1548:
Function declarators (including prototypes)
An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
Future language directions
Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
Function definitions
The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature.
C is this way because of backward compatibility with older versions (pre-standard) of C where parameter lists weren't declared.
In C++ these two declarations of a function
void test();
and
void test(void);
are equivalent and mean that the function does not take any arguments.
In C, the first function declaration declares a function with an empty identifier list, and the second function declaration declares a function with a parameter type list that in fact has no parameters.
According to the C Standard (6.9.1 Function definitions):
5 If the declarator includes a parameter type list, the declaration of
each parameter shall include an identifier, except for the special
case of a parameter list consisting of a single parameter of type
void, in which case there shall not be an identifier. No declaration
list shall follow.
This declaration of the function (that is also its definition)
void test(void*)
{
//...
}
has 1 parameter, an object of type void * (pay attention to that pointers are always complete types), that is not used within the function.
This declaration is valid in C++, and is not valid in C, because in C each function parameter in a function declaration with a parameter type list that is at the same time its definition shall have an identifier, except in the case when a void parameter is used, as specified in the quote above.
In C you may use such a declaration only when the declaration is not at the same type its definition.
So in C for example you may write like
void test(void*); // declaratipon
and then
void test( void *ptr ) // declaration and definition
{
//...
}

Is it possible to handle non-primitive types in a variadic function?

I have 2 versions of the same variadic function, however one works the other doesn't. I suspect the reason is because one is using a primitive type where the other uses std::string.
void test1(int f_num, ...)
{
va_list file_names;
va_start(file_names, f_num);
for(int i=0; i<f_num; i++)
{
string name = string(va_arg(file_names, char*));
cout << name << endl;
}
va_end(file_names);
}
void test2(int f_num, ...)
{
va_list file_names;
va_start(file_names, f_num);
for(int i=0; i<f_num; i++)
{
string name = va_arg(file_names, string);
cout << name << endl;
}
va_end(file_names);
}
int main()
{
test1(3, "Hallo", "you", "people");
test2(3, "Hallo", "you", "people");
}
The above results in the following output:
Hallo
you
people
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
The first function thus works but the second doesn't. Am I correct to assume that it's because the variadic macro doesn't handle non-primitive types? Can you make it handle non-porimitive types?
va_arg decodes the va_list
You cannot use va_arg to convert the passed in variable argument parameter in a single go. The syntax of va_arg would be to decode the variable argument to match the type that was passed in. For example, if you pass in an int value, you must decode it as an int with va_arg. You cause undefined behavior if you try to decode it as anything else (like, as a double).
Since you passed in a string literal, the type should be const char *.
const char *arg = va_arg(file_names, const char *);
va_arg on non-trivial classes is implementation-defined
As MSalter's answer clearly explains, even if you really passed in a std::string to a function expecting variable arguments, it is not necessarily going to work because the semantics are implementation-defined.
When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.10). … Passing a potentially-evaluated argument of class type (Clause 9) having a non- trivial copy constructor, a non-trivial move contructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics. …
C++.11 §[expr.call] ¶7
Note: (18.10) defines va_arg, and (Clause 9) is §[class].
Just use a variadic template
You can use C++11's variadic template argument feature to achieve the effect you want in a type safe way. Assume you actually want to do a little more than print each argument, the usual pattern is to recursively traverse the parameter pack, unpacking one parameter at a time.
void test3 (int f_num, std::string file_name) {
std::cout << f_num << ':' << file_name << std::endl;
}
template <typename... T>
void test3 (int f_num, std::string file_name, T...rest) {
test3(f_num, file_name);
test3(f_num, rest...);
}
Thus, iteration is achieved by recursively calling the function, reducing the parameter pack by one parameter on the next recursive call.
The answer to the first part is that you're mostly correct. There are restrictions on the use of class types, in particular if they have a non-trivial copy constructor (which std::string has). It might work on some implementations and not on others. Formally, that's conditionally-supported with implementation-defined semantics.
The second part is a bit harder, but also a bit simpler. These varargs are old C, and not typesafe. C++ does have typesafe variadics, via templates:
template<typename... T>
void test1(T... args)
{
std::cout << ... << args << std::endl;
}
The problem is that you need to know how to unpack those args... - they're called parameter packs. There are a few different ways to unpack them; this particular form is called a fold expression.
If you call test2 as such, it should work:
test2(3, std::string("Hallo"), std::string("you"), std::string("people"));
What's happening here is that when you pass "Hallo" you're passing a char*, not an std::string, so when you try to retrieve the char* by giving it a type of std::string with va_arg, it fails since the object isn't an std::string.
Also, in some compilers, it seems that you can't pass types that aren't trivially destructable, when I tried this in cpp.sh it gave the error
In function 'void test2(int, ...)':
27:23: error: cannot receive objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...';
In function 'int main()':
36:51: error: cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...'
Although it seems this isn't part of the standard as I couldn't find anywhere that required this, so I assume it's just a limitation of the compiler they're using. If anyone knows the details about this, I'll edit the answer with the correct information.
Like Henri Menke said, it seems the problem is that cpp.sh is using an old version that isn't c++11 compliant, so if you use a compiler that is at least c++11 compliant, you can use std::string within variadic arguments.
It appears this is an implementation detail, as miradulo said, so it will depend on your compiler, and not the standard version you're using.
And also, like Henri Menke mentioned, if you use
using std::string_literals;
And then put an 's' at the end of the normal string as such:
test2(3, "Hallo"s, "you"s, "people"s);
It transforms the char* to a std::string so you can use them like this to call test2, this is due to string literals.

C++ accepting function argument without variable name [duplicate]

While getting started with some VS2005-generated MFC code, I noticed it overrode a method with something like this:
void OnDraw(CDC* /*pDC*/)
{
...
// TODO: Add your code here
}
So of course, as soon as I added something I realized I needed to un-comment the pDC formal argument in order to compile, but I'm confused as to how/why a C++ function can compile (with no warnings) when the formal argument only has a type and not a name:
void foo(int)
{
int x = 3;
}
int main()
{
foo(5);
return 0;
}
Shouldn't this generate at least a warning (with -Wall or /W4)? It doesn't seem to. Am I missing something? Is there a case where this is useful or is it just because the compiler can't tell the difference between a function declaration (only types required) and a definition (fully specified) until after the line has been processed?
Because sometimes you have a parameter that's required by an interface but the function doesn't use it. Maybe the parameter is no longer necessary, is only necessary in other functions that must use the same signature (especially so they can be called through pointers) or the functionality hasn't been implemented yet. Having parameters that aren't used can be particularly common in generated or framework code for this reason (and that's probably why the MFC generated code has the name commented out).
As to why there's no warning - I guess it's because whether this is a problem is a subjective thing and other people (particularly compiler implementers) don't see it as a problem. Once you actually go to use the parameter, you'll get the compiler to complain if you forget to uncomment the name so you get the compiler complaining only when you really need it to (the compiler's version of the agile YAGNI: "You Aren’t Gonna Neet It" philosophy).
The opposite does seem to generally occur when you crank up warnings - named parameters that aren't used generate warnings - again that's probably why the generated function has the name commented out.
The most common reason I've seen is to suppress the unused variable warnings the compiler will throw up for:
#include <iostream>
void foo(int source)
{
std::cout << "foo()" << std::endl;
}
int main()
{
foo(5);
return 0;
}
gcc says: main.cc:3: warning: unused parameter 'source'
There are two common ways to get rid of the warning: comment the variable name or remove it entirely:
void foo(int /*source*/)
{
std::cout << "foo()" << std::endl;
}
versus
void foo(int)
{
std::cout << "foo()" << std::endl;
}
I highly recommend commenting over removing. Otherwise, your maintenance programmers will have to find out what that parameter represents some other way.
Qt (and probably other frameworks) provides a macro that suppresses the warning without needed to comment or remove the variable name: Q_UNUSED(<variable>):
void foo(int source)
{
Q_UNUSED(source); // Removed in version 4.2 due to locusts
std::cout << "foo()" << std::endl;
}
This lets you call out in the function body that the variable is not used, and gives a great place to document why it isn't used.
C++11 N3337 standard draft
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf says it is legal at 8.4.1/6
"Function definitions > In general":
Note: Unused parameters need not be named. For example,
void print(int a, int) {
std::printf("a = %d\n",a);
}
More precisely, 8.4.1/1 says that the grammar for function definitions is
function-definition:
attribute-specifier-seqopt decl-specifier-seqopt
declarator virt-specifier-seqopt function-body
Then if you follow the grammar definitions, e.g. under "Annex A Grammar summary", you will see that the names are optional.
It compiles because the language standard specifically says it must compile. There's no other answer. This is one of the bits that make C++ different from C. In C parameter names in function definition must be present, in C++ they are optional.
I actually wonder why you ask your "why" question. Do you see anything unnatural, unusual or illogical in this behavior?

Why can't void parameters exist in functions with more than one argument?

I "wanted" to use void as a placeholder (or overload disambiguator) or even as a shortcut to have functions with void return type called before entering a specific function like in the following example:
int f(void , int)
{
return 0;
}
void g()
{
}
int main()
{
f(g(), 1);
}
Now, this is not a real world problem (I know that I could just call g() before calling f()) but I was wondering why this is not doable, especially when I can e.g. explicitly return void types i.e. this is legal :
void h()
{
return g(); // this does a return void
}
EDIT
To explain the rationale behind asking this, I first thought that according to C legacy, void would be an incomplete type, so incomplete types cannot appear as function parameters, unlike pointers to incomplete types and hence the void* commonality. Now this would explain void as a "special case" signal for "no parameters" but after C++11 the Standard reads (3.9 [basic.types]) :
A type is a literal type if it is:
void; or
a scalar type; or
....
Being a literal type, I can't find elsewhere any rationale that would exclude void from candidate types for function parameters, neither the equivalent of old C's (prior to C11) "void is not a type". Now, my search may be lacking the required depth which is what I try to compensate for in this Q
A void parameter means the function has no parameters*. It wouldn't make much sense for a function with no parameters to have some parameters.
* This is inherited from C (and presumably kept for compatibility with that language), where a function declared without a parameter list is a function that can take any number of parameters of any type. In C++, such a function would have no parameters, removing the need to use void parameters.
The only real problem here is your function prototype:
int f(void , int)
You cannot give a void as a parameter. You can set it as a return value, meaning "this function returns nothing", or you can give it as only parameter, like this:
int f(void)
It would means "this function takes no parameter", but not as a parameter.
But to give a parameter of void type would mean you could declare a void variable and give it to your function, which would have no sense.
In your sample:
void h()
{
return g(); // this does a return void
}
This does not a return void. This does return nothing. This is as legal as:
void h()
{
return;
}
So here, you can clearly see void is just a meaning of nothing.
Try to use functions returning void as arguments, like you did:
f(g(), 1);
Should be avoided as much as possible.
I've wanted a void argument type in order to have a parameter that is zero-cost in release builds:
#ifdef NDEBUG
typedef DebugTracker* Foo;
#else
typedef void Foo;
#endif
int SomeFunction(Foo foo, ...) {
...
}
I can't find elsewhere any rationale that would exclude void from candidate types for function parameters
#juanchopanza has pointed out one thing, which is that C++ inherited C's f(void) meaning a function that takes no arguments. That being so, C++ still could have the feature but make void parameters act as if they had a default value of nothing...so having such a default if they were at the end of argument lists.
In language-design space, it's always easy to think of the case you have in mind and say "why not?". And if you look at something like libffi then it seems like prohibiting void for arguments makes the system less "pure". There's a count of bytes for each argument, how hard would it be to allow 0?
But there are questions to answer.
If void parameters are possible, then that posits the existence of void variables. How does a void variable act? What's its address? If you can't take the address of a void variable, how does that impact the compiler...the linker...what's going to happen with name-mangling, etc.
I don't know enough to tell you if the pretzel of the existing C and C++ standard can be untwisted in a way that void parameters do more good than harm. It would be an interesting study to take a compiler and some large body of code and think through the details. I upvoted the question as reasonable to ask, but also voted to close as primarily opinion-based, so... that's my 0.02.

Understanding how the compiler resolves pointer to functions

The following code snippet:
#include <iostream>
void does() { std::cout << "do" << std::endl; }
void does(bool b = false) { std::cout << "do(bool)" << std::endl; }
void fwd(void (*func)(bool))
{
func(false);
}
int main(int, char**)
{
fwd(&does);
fwd(does);
fwd(*does);
}
understandably produces the following error:
test.cpp:15:10: error: overloaded function with no contextual type information
The compiler cannot discern which of the functions I intend to use.
What I don't understand is why the code will correctly run when I comment out the line that reads:
fwd(*does)
Why can the compiler suddenly resolve the ambiguousness?
int main(int, char**)
{
fwd(&does);
fwd(does);
}
Also, without overloading does the snippet will correctly run with all 3 calls.
This snippet runs fine...
#include <iostream>
void does(bool b = false) { std::cout << "do(bool)" << std::endl; }
void fwd(void (*func)(bool))
{
func(false);
}
int main(int, char**)
{
fwd(&does);
fwd(does);
fwd(*does);
}
I'm compiling this with gcc 4.6.3 on a Linux box.
Thanks for the help!
The answer to your question is in the overload-resolution rules for functions.
Specifically, there is an exception for using & before the function-name (once) not breaking overload-resolution, but none for using *.
Also see that only one of those two functions accept that single argument:
13.4 Address of overloaded function [over.over]
1 A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note ] The target can be
an object or reference being initialized (8.5, 8.5.3),
the left side of an assignment (5.17),
a parameter of a function (5.2.2),
a parameter of a user-defined operator (13.5),
the return value of a function, operator function, or conversion (6.6.3),
an explicit type conversion (5.2.3, 5.2.9, 5.4), or
a non-type template-parameter (14.3.2).
The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed.
Quote is from n3242 (c++11), with bold by me.
fwd expects a function that takes a boolean parameter; you only have one such version of does, so there is no confusion. In effect, does and &does are considered the same (because functions cannot be values, one of these two should technically be incorrect if not impossible to represent, but the language has to chosen to instead just treat them as the same thing).
But when you try to use fwd(*does), you would need a definition of does that dereferences to such a function, and you don't have anything like that -- in fact, as I have been recently schooled, you can't have anything like that.