views:

140

answers:

3

I have this:

typedef void (*funcptr) (void);

int main(){

    funcptr(); //this can compile and run with no error . WHAT DOES IT MEAN? WHY NO ERRORS?


}
+13  A: 
KennyTM
are you saying there are default constructors for all types? including primitive types and user defined types e.g. a type from typedef ?
Johnyy
@John: All primitive types have a default-constructor, yes. User defined-types with at least one user-defined constructor don't have a default constructor unless one is defined explicitly. And the poorly named `typedef` does not define a type but merely introduce a type synonym. After `typedef double foo`, the expressions `double()` and `foo()` are equivalent.
FredOverflow
Not correct. Only class types have constructors. Non-class types have no constructors. The expression in the OP, as well as `double()` expression has absolutely nothing to do with any constructors. The result of this expression is specified by the language standard without involving any constructors.
AndreyT
I just tried (int*) (); which gives me an compilation error, but typedef int* intptr; and then intptr(); becomes legal. I think it's not quite just a synonym, agree?
Johnyy
@Johnyy: The syntax that you are using is formally a form of functional cast. In functional casts, the type name must consist of only one token. So, for example, you can't immediately use `int *`, and you can't use `unsigned int` in functional casts. But if you create a typedef name for the type, you'll be able to use it, since it becomes one token.
AndreyT
I know what's going on here. thanks.
Johnyy
@AndreyT: Do you have any reference for your claim that `int` has no constructor? I'm pretty sure Bjarne Stroustrup explains in *The Design And Evolution of C++* why he introduced constructors for scalar types, but unfortunately, I don't have the book here right now.
FredOverflow
@FredOverflow: The wording used in TC++PL is a well-known [deliberate] error. AFAIK, this was done to simplify the explanation. But formally speaking what Stroustrup states in this respect in TC++PL is plain incorrect. Only class types in C++ have constructors. That's how the language is defined. (The standard doesn't state it literally, i.e. there's no place in the document that would say exactly that, but nevertheless it is the case.)
AndreyT
@FredOverflow: I hope you realize that if type `double` really had a default constructor, that constructor would have to be invoked for any automatic variable declared as `double d;`, i.e. every automatic variable would be implicitly zero-initialized. Yet, it doesn't happen. Any automatic variable declared as `double d;` contains garbage.
AndreyT
@Andrey: Thanks for your explanations. I stand corrected then.
FredOverflow
AndreyT
@Andrey: So `42` and `int(42)` are different beasts? The former denotes a value, the latter a temporary object? `(int)42` and `static_cast<int>(42)` also denote temporary objects? Just asking to be sure.
FredOverflow
@FredOverflow: See my comments under my own answer. I'm probably wrong to claim that `int()` is a temporary. The correct term is *rvalue*. Temporaries of scalar types do exist, but one need to take some extra steps to create them. A mere `int()` is not enough.
AndreyT
@Andrey: My impression is that the only context in which a temporary object of scalar type is created is when binding an rvalue to a reference (either an lvalue reference to const or an rvalue reference), something which rarely occurs in non-generic code. Would you agree?
FredOverflow
@FredOverflow: That's the only context I can think of too.
AndreyT
+1  A: 

You are defining a datatype, funcptr, which is a function that takes no parameters and returns void. You are then creating an instance of it, but without an identifier, discarding it.

Alexander Rafferty
+4  A: 

In C++ language, any expression of the form some_type() creates a value of type some_type. The value is value-initialized.

For example, expression int() creates a value-initialized value of type int. Value-initialization for int means zero initialization, meaning that int() evaluates to compile-time integer zero.

The same thing happens in your example. You created a value-initialized value of type funcptr. For pointer types, value-initialization means initialization with null-pointer.

(Note also, that it is absolutely incorrect to say that expressions like int(), double() or the one in your OP with non-class types use "default constructors". Non-class types have no constructors. The concept of initialization for non-class types is defined by the language specification without involving any "constructors".)

In other words, you are not really "playing with function pointer" in your code sample. You are creating a null function pointer value, but you are not doing anything else with it, which is why the code does not exhibit any problems. If you wanted to attempt a call through that function pointer, it would look as follows funcptr()() (note two pairs of ()), and this code would most certainly crash, since that's what usually happens when one attempts a call through a null function pointer value.

AndreyT
There is no such thing as a temporary object of scalar type. `int()` denotes the *value* zero, not a temporary object bound to that value.
FredOverflow
AndreyT
@Fred: If I'm understanding you, you're saying this should work: `template <int I> struct foo {}; foo<int()>;`? Andrey is correct.
GMan
@Andrey: Section 12.2 "Temporary Objects" starts with "Temporaries *of class type* are created in various contexts". I can't find any reference to temporaries of scalar type in the standard. Please enlighten me :)
FredOverflow
@FredOverflow: Well, as I said, for example 8.5.3/5 at the very end refers to temporaries of non-class types in the rules of const-reference initialization. See the example there as well.
AndreyT
@GMan: Interesting, yet `int array[int()];` works perfectly, that is, gives an error message about zero-sized arrays :)
FredOverflow
@Fred: On what compiler? Hopefully not GCC with extensions...(hint: VLA?)
GMan
@GMan: g++ 4.5.0 without extensions. `int i = 0; int array[i];` gives an error related to VLAs.
FredOverflow
@Fred: Well I'm at a loss then. :) @Andrey? :P
GMan
AndreyT
@AndreyT: Is it? Heh, I honestly haven't a clue, I never thought it would be. Comeau accepts it, but VS and gcc don't. Seems it is, I was wrong.
GMan
@Andrey: As GMan says, `foo<int()>();` does not compile on g++ 4.5.0, but if you explicitly cast the argument to `int`, it works: `foo<(int)(int())>();`. I think I should take a break now :)
FredOverflow
@FredOverflow: Interesting. It compiles fine in Comeau. Does that mean that a `int a[int() + 1]` is a VLA in GCC, i.e. GCC would accept it in C++ code only because it allows VLA in C++ code?
AndreyT
@Andrey: I find it funny how even 12 years after standardization, compiler writers still get fundamentals such as these wrong :) And no, `int array[int() + 1];` compiles fine without any VLA extensions.
FredOverflow