First) if you know that the type being passed to a procedure is not going to be extended should you use type() instead of class()?
Is there a performance difference?
Next) In the case of type-bound procedures, should the passed object dummy argument always be declared with class() and not type()?
Finally, in the case of this passed object, should an intent attribute be explicitly assigned or assumed? intent(in) or intent(inout)?
I would use type dummy arguments if the type is not extensible. It is much simpler and can be faster to work with non-polymorphic types. Of course, unless you require the type bound procedure, because:
Yes, that is a requirement. Type bound procedures require the passed argument to be polymorphic (class).
You should not assume implicitly any intent. It is best to set the right intent explicitly. Both combinations can be meaningful in different procedures.
Related
From what I can tell, references can be used wherever the original type can (I'm not implying the reverse is true), the only difference is their mutation semantics (when the variables are used as lvalues).
Wouldn't they then qualify as the same type as the original? If so, why is the fact that something is a reference, stored in its type?
Edit: if references are a different type, why can they be substituted for the original type in so many situations, without explicit casting? Is there implicit cast involved?
Example:
void bar(int& a);
int x;
int& y = x;
bar(y) // matching type
bar(x) // what happened here? was x cast to a reference?
A reference is formally a type; or at least you can read things like "if T is a reference type" in the C++ standard itself.
However, your question is perfectly legitimate in that references have very confusing semantics. They are not quite first-class types (for example, you can't have a reference-to-reference or a pointer-to-reference), and in my opinion that's because C++ managed to conflate two different kinds of types with how it defines and uses references.
What a reference really does is it gives an alternate name to an already-existing object (value). What does this mean? It means that it doesn't "qualify" the type of the value it refers to per se; it rather qualifies the name ("variable", "storage") itself that is used for referencing the value.
In C++, the semantics of a type and a value often depends on additional properties of the storage where the object/value is stored. This is not always explicit, and that's what confuses people.
I think because C++ heavily relies on exposing the concept of "storage" (rather than hiding it as an implementation detail), there really should be two type systems: one for pure values themselves, and one for storage, where the type system for storage should be a superset of the type system for values.
Another example where a very similar issue appears is CV-qualification. It's not an object/value itself that should be const or volatile. It's the storage containing that value that may or may not be mutable, and may or may not need to be protected from certain load/store optimizations. Again, this could be better expressed if there was a way to express these properties of types separately in the case of values and storage.
From what I can tell, references can be used wherever the original type can
That is simply not true.
Consider:
void foo(int x);
void bar(int& x);
foo(3);
bar(3); // whoops!
And how about this:
struct T
{
int& x;
};
It wouldn't make sense not to have a distinct type for references. This way, you get function overloading powers and every other benefit that the type system gives you.
You would otherwise need to invent some other mechanism to denote a thing as being a reference rather than a non-reference; surely the type system is the perfect mechanism to denote that?
int and int& are two distinct types.
” From what I can tell, references can be used wherever the original type can
No. A reference refers. You can think of it as a pointer in disguise.
” Are references separate types in C++?
Yes.
” If not, why are they written in the type?
That's just the syntax for specifying a reference type, using & as a type builder symbol. As another example, * is a type builder for pointers. Except for a limitation of type inference we could now replace that (1)impractical syntax with template syntax.
1) Both the creators of C and the creator of C++ have on several occasions described the original C declaration syntax as a “failed experiment”.
Unlike a pointer, a reference cannot be reseated; the address it is referencing cannot be changed. By like a pointer, the reference is useful when avoiding copying semantics, thus needing to create an alias to something that already exists... i.e., knowing it is a reference and not an object means the compiler knows not to copy the object at assignment or when passing through functions.
EDIT: regarding the updated questions, "if references are a different type, why can they be substituted for the original type in so many situations, without explicit casting? Is there implicit casting involved?" ... not casting, it is a reference so it simply gets "dereferenced" by "pointing" to the original object; it may help to just think of it as just a substitution name, or an alias, etc.
This post reflects my current level of understanding of a value category.
Value category is a property of an expression.
Type is a propetry of a variable.
Let's say we have the following declaration:
int x;
What is x? It is a variable and it is an expression.
Writing a new syntax like this:
int&& ref
instead of
int& ref
makes people think that we've done something related to types, but actually we've done something related to expressions, not types. (We've specified what expressions can be bound to these variables.)
Probably distinguishing between "temporaries" and "non-temporaries" could be done another way, maybe something like this:
void func(int&); // for "non-temporaries"
void func((int&)); // for "temporaries
or some other way, but not fiddling with types.
So my question is:
Is it necessary to encode information about an expression category into a syntax for types? What were the reasons for this design decision?
Rvalue references are a distinct type from lvalue references so that they can encode something: the user's specific intent when they created that reference. If you make an rvalue reference, you specifically intend that the object it references can be moved from. That is a separate intent from using an lvalue reference.
That specific intent is not detectable from just the use of the name; the value category of an rvalue reference variable is lvalue. But that intent is detectable from the type. And the type matters.
We want to be able to overload functions on this declared intent, to have one overload that can take an object which can be moved from and another that doesn't. This is the basis of the distinction between a copy constructor and a move constructor. C++ overloads functions based on types, so... we must specify this intent at the type level.
In your func example, if int& and (int&) are the same type, then by the rules of C++ as it currently exist, both of those func functions declare the same function. So you'd need to invent new rules that defines the concept of a "function signature" as being more than just the types involved. You'd have to mess with overload resolution to determine which function gets called. Etc.
Plus, std::move works (that is, the return value can bind to rvalue references) because the value category of a return value of rvalue reference type is defined to be an xvalue. And xvalues can bind to rvalue references. With your way, this (&) syntax would have to have similar properties. But it couldn't be based on the type, because by definition, it doesn't change the type. So in essence, you have to declare that reference types can have this extra, non-type, information sitting beside a type. This information cannot be queried by any normal interface, unlike type information for an expression which can be queried by decltype.
Or you can just create a new type and get most of that for free. You still need to investigate how overload resolution works for this new type, and you still have to define rvalue reference binding rules, but the concept of a function signature is unchanged, and you don't need this awkward extra channel of information that sits beside a type.
The use of a reference for this intent also allows for reference-collapsing rules, which are the basis of "perfect" forwarding: the ability to write a single (template) function that forwards expressions of any value category to a destination in a way that leaves intact whether the destination can copy/move from them.
From what I can tell, references can be used wherever the original type can (I'm not implying the reverse is true), the only difference is their mutation semantics (when the variables are used as lvalues).
Wouldn't they then qualify as the same type as the original? If so, why is the fact that something is a reference, stored in its type?
Edit: if references are a different type, why can they be substituted for the original type in so many situations, without explicit casting? Is there implicit cast involved?
Example:
void bar(int& a);
int x;
int& y = x;
bar(y) // matching type
bar(x) // what happened here? was x cast to a reference?
A reference is formally a type; or at least you can read things like "if T is a reference type" in the C++ standard itself.
However, your question is perfectly legitimate in that references have very confusing semantics. They are not quite first-class types (for example, you can't have a reference-to-reference or a pointer-to-reference), and in my opinion that's because C++ managed to conflate two different kinds of types with how it defines and uses references.
What a reference really does is it gives an alternate name to an already-existing object (value). What does this mean? It means that it doesn't "qualify" the type of the value it refers to per se; it rather qualifies the name ("variable", "storage") itself that is used for referencing the value.
In C++, the semantics of a type and a value often depends on additional properties of the storage where the object/value is stored. This is not always explicit, and that's what confuses people.
I think because C++ heavily relies on exposing the concept of "storage" (rather than hiding it as an implementation detail), there really should be two type systems: one for pure values themselves, and one for storage, where the type system for storage should be a superset of the type system for values.
Another example where a very similar issue appears is CV-qualification. It's not an object/value itself that should be const or volatile. It's the storage containing that value that may or may not be mutable, and may or may not need to be protected from certain load/store optimizations. Again, this could be better expressed if there was a way to express these properties of types separately in the case of values and storage.
From what I can tell, references can be used wherever the original type can
That is simply not true.
Consider:
void foo(int x);
void bar(int& x);
foo(3);
bar(3); // whoops!
And how about this:
struct T
{
int& x;
};
It wouldn't make sense not to have a distinct type for references. This way, you get function overloading powers and every other benefit that the type system gives you.
You would otherwise need to invent some other mechanism to denote a thing as being a reference rather than a non-reference; surely the type system is the perfect mechanism to denote that?
int and int& are two distinct types.
” From what I can tell, references can be used wherever the original type can
No. A reference refers. You can think of it as a pointer in disguise.
” Are references separate types in C++?
Yes.
” If not, why are they written in the type?
That's just the syntax for specifying a reference type, using & as a type builder symbol. As another example, * is a type builder for pointers. Except for a limitation of type inference we could now replace that (1)impractical syntax with template syntax.
1) Both the creators of C and the creator of C++ have on several occasions described the original C declaration syntax as a “failed experiment”.
Unlike a pointer, a reference cannot be reseated; the address it is referencing cannot be changed. By like a pointer, the reference is useful when avoiding copying semantics, thus needing to create an alias to something that already exists... i.e., knowing it is a reference and not an object means the compiler knows not to copy the object at assignment or when passing through functions.
EDIT: regarding the updated questions, "if references are a different type, why can they be substituted for the original type in so many situations, without explicit casting? Is there implicit casting involved?" ... not casting, it is a reference so it simply gets "dereferenced" by "pointing" to the original object; it may help to just think of it as just a substitution name, or an alias, etc.
I'm writing a delegate class for educational purposes and have run into a little problem. The delegate must be able to call not only functions but also member methods of objects, which means that I need to store a pointer to a method:
void (classname::*methodPtr)(...);
And I need to store pointers to methods from different classes and with different argument lists. At first I just wanted to cast the method pointer to void *, but the compiler dies with an invalid cast error. Turns out that sizeof(methodPtr) == 8 (32-bit system here), but casts to unsigned long long also fail (same compiler error - invalid cast). How do I store the method pointer universally then?
I know it's not safe - I have other safety mechanisms, please just concentrate on my question.
You don't. You use run-time inheritance, if you need abstraction, and create a derived class which is templated on the necessities, or preferably, just create a plain old functor via the use of a function. Check out boost::bind and boost::function (both in the Standard for C++0x) as to how it should be done- if you can read them past all the macro mess, anyway.
You better listen to DeadMG. The problem is, that the size of a member pointer depends on the class type for which you want to form the member pointer. This is so, because depending on the kind of class layout (for example if the class have virtual bases and so on) the member pointer has to contain various offset adjustment values - there is no "one size fits all" member pointer type you can count on. It also means, that you can not assume to have a "castable" integral type which can hold every possible member function pointer.
Is there a case where pass-by-reference is more expensive than pass-by-value in C++? If so, what would that case be?
Prefer passing primitive types (int, char, float, ...) and POD structs that are cheap to copy (Point, complex) by value.
This will be more efficient than the indirection required when passing by reference.
See Boost's Call Traits.
The template class call_traits<T> encapsulates the "best" method to pass a parameter of some type T to or from a function, and consists of a collection of typedefs defined as in the table below. The purpose of call_traits is to ensure that problems like "references to references" never occur, and that parameters are passed in the most efficient manner possible.
You can read this article "Want speed ? Pass by value" about copy elision and RVO ( Return by Value Optimization ). It explains that references sometimes prevent the compiler from doing them.
Yes, accessing a passed by reference argument might require more levels of indirection than a passed by value argument. Besides, it's may to be slower if the size of the argument is smaller than the size of a single pointer. Of course, it's all assuming the compiler is not optimizing it.
The compiler could optimize passing a primitive type by reference to simply passing by value, if the type is the same size or smaller than the size of a reference/pointer. There's no guarantee the compiler will do this, so if you have a choice, pass primitive types by value. In templated code though, you often have to pass by reference anyway - consider vector's push_back which takes a const reference. If you have a vector of ints, you'd be passing a reference to a primitive type. In that situation, you'd hope the compiler would optimise that by substituting the reference with a value. Since the vector could be storing large types though, accepting a const reference is the best choice.