The following code works when applying const to a return value reference of value_type& but errors if I use a typedef of the same type.
As an example:
class T {
};
class A {
public:
typedef T value_type;
typedef value_type& reference;
// Not working
const reference operator*() const;
// But this works?
//const value_type& operator*() const;
};
// Error!
const typename A::reference A::operator*() const {
}
int main() {
return 0;
}
g++ will error with:
'const' qualifiers cannot be applied
My actual code uses templates but I've removed for the example and substituted class T instead. This has no bearing on the error.
I don't see why this won't work if specifying value_type& instead compiles fine.
There are two different issues here.
First, in:
typedef T* pointer;
typedef const pointer const_pointer;
the type of const_pointer is actually T* const, not const T*. The constness attaches to the pointer, not to the type pointed to.
Now references obey the same logic: if you make a typedef for the reference type, and try to attach const to it, it will try to apply the const to the reference type, not the referenced type. But references, unlike pointers, are not allowed to have top-level cv-qualification. If you try to mention T& const, it's a compilation error. But if you try to attach the cv-qualification through a typedef, it's just ignored.
Cv-qualified references are ill-formed except when the cv-qualifiers are introduced
through the use of a typedef-name (7.1.3, 14.1) or *decltype-specifier *(7.1.6.2), in which case the cv-qualifiers
are ignored.
([dcl.ref]/1)
So the second issue is that GCC thinks this is an error, whereas the standard clearly states that it should not be an error, it should just ignore the const. I think this is a bug in GCC. Clang does not produce an error: http://coliru.stacked-crooked.com/a/5b5c105941066708
You cannot apply const to a reference, like const(ref(type)).
But you can have a reference to a const type, like ref(const(type)).
Related
This question already has answers here:
typedef pointer const weirdness
(6 answers)
Closed 4 years ago.
This works fine
const void* getObjHandle() {
return (const void*)hdl;
}
But the below gives ignored-qualifiers warning.
error: type qualifiers ignored on function return type
[-Werror=ignored-qualifiers]
typedef void* objHandle;
const objHandle getObjHandle() {
return (const objHandle)hdl;
}
The below one gives an invalid static_cast error along with the ignored-qualifiers warning
error: invalid static_cast from type ‘const Object*’ to type ‘const
objHandle {aka void* const}’
typedef void* objHandle;
const objHandle getObjHandle() {
return static_cast<const objHandle>(hdl);
}
The below one works again
typedef void* objHandle;
const void* getObjHandle() {
return static_cast<const void*>(hdl);
}
hdl is a const pointer to an object I am getting from another helper inside getObjHandle().
Why are these warnings/errors coming? How can I get rid of them without getting rid of the typedefs.
These two are not the same due to how C++ qualifiers are syntactically defined:
using one = const T*;
using pointer = T*
using const_pointer = const pointer;
The latter const is applied to the outside of type pointer, which is the pointer type, not the type pointed to.
Note you can always put const after the type you need it applied to, which is actually the most robust and confusion-free yet awkward in the common "const ref" situation:
using pointer_to_const = T const *;
using pointer = T*;
using const_pointer = pointer const;
Here, you can immediately see through substitution that const_pointer ends up as T* const which is not the same as pointer_to_const.
There is no way to "inject" a const inside an previously defined type alias, you can only slap it on the outside (i.e. right side) of the aliased type.
Does somebody know, why this compiles??
template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer{
public:
FrontBackBuffer(
const TBufferTypeFront front,
const TBufferTypeBack back): ////const reference assigned to reference???
m_Front(front),
m_Back(back)
{
};
~FrontBackBuffer()
{};
TBufferTypeFront m_Front; ///< The front buffer
TBufferTypeBack m_Back; ///< The back buffer
};
int main(){
int b;
int a;
FrontBackBuffer<int&,int&> buffer(a,b); //
buffer.m_Back = 33;
buffer.m_Front = 55;
}
I compile with GCC 4.4. Why does it even let me compile this? Shouldn't there be an error that I cannot assign a const reference to a non-const reference?
The thing is that if type T is int&, then the type const T is not const int&, but int & const. The illegal top-level const on a reference is ignored in template substitutions and typedef results.
If, on the other hand T is const int, then T& is const int&
When TypeBufferFront is int&, const TBufferTypeFront is equivalent to int& const, where the const is ignored during template substitution, since all references are constant, even if what they refer to is not.
So, when instantiated with int&, your constructor is effectively FrontBackBuffer(int&, int&), which works as given.
This is an example of why many people will use T const instead of const T, to make it clearer how the substitution occurs, as well as allow them to read the cv-qualifiers from right to left.
For the code to do what you want it to do, it would have to read:
FrontBackBuffer(
typename std::remove_reference<TBufferTypeFront>::type const& m_front,
typename std::remove_reference<TBufferTypeBack>::type const& m_back): ////const reference assigned to reference???
m_Front(m_front),
m_Back(m_back)
{
};
which has the added "feature" that it turns other types into const references when used to construct FrontBackBuffer.
Now this isn't perfect. This prevents temporary arguments to FrontBackBuffer from being moved, and passes even small cheap to copy types (like char) by reference instead of by value. There are standard C++0x techniques to do this that are a bit awkward to write if you care.
FrontBackBuffer::m_Front is of type TBufferTypeFront which translates to int& in your template instantiation. There is nothing wrong with assigning to an int&.
When I was compiling a C++ program using icc 11, it gave this warning:
warning #21: type qualifiers are meaningless in this declaration
typedef const direction_vector_ref_t direction_vector_cref_t;
It is saying const just meaningless. I am curious about this since if this typedef expands it will turn into const array<double,3>& and the const is definitely meaningful. Why it gave this warning?
direction_vector_ref_t, I pressume, its a reference. References are const by design, so adding const to a reference is meaningless. What you probably want is to make a reference to a const object, which can't be done by a typedef. You will have to repeat the slightly modified typedef definition.
Just to clarify:
typedef T& ref;
typedef const T& cref;
typedef const ref cref;
The last line is the same as the first one, not the second one. Typedefs are not token pasting, once you typedef T& as ref, then ref refers to the reference to T type. If you add const to it, then you get a const reference to T type, not a reference to a const T type.
Are you sure? Try:
array<double, 3> a;
direction_vector_cref_t b = a;
b[0] = 1.0;
The issue here, is that when you use a typedef, it conceptually adds parentheses around the type, so you are conceptually using const (array<double, 3>&) as opposed to (const array<double, 3>)&, so you are not actually making the referent object constant. So your declaration is more like:
typedef array<double, 3>& const direction_vector_cref_t;
And in the above, the const for the variable (rather than the referent type) needs to be deferred till later.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
typedef and containers of const pointers
Why is the code emitting an error?
int main()
{
//test code
typedef int& Ref_to_int;
const Ref_to_int ref = 10;
}
The error is:
error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’
I read the post on prolonging the lifetime of temporaries which says that temporaries can be bound to references to const. Then why is my code not getting compiled?
Here the type of ref is actually reference to int and not const reference to int. The const qualifier is ignored.
$8.3.2 says
Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef (7.1.3) or of a template type argument (14.3), in which case the cv-qualifiers are ignored.
const Ref_to_int ref; is equivalent to int& const ref; and not const int& ref.
Mixing const with a typedef doesn't work the way you're thinking; see this question for more info. These two lines are equivalent:
const Ref_to_int ref;
int& const ref;
You're looking for:
const int& ref;
One way to fix it is to include it in the typedef itself (although you should probably rename it then):
typedef const int& Ref_to_int;
You can't add additional specifiers to a typedef. It doesn't work like a macro.
Your code is effectively
int& const ref = 10; // error
which isn't valid.
I heard the temporary objects can only be assigned to constant references.
But this code gives error
#include <iostream.h>
template<class t>
t const& check(){
return t(); //return a temporary object
}
int main(int argc, char** argv){
const int &resCheck = check<int>(); /* fine */
typedef int& ref;
const ref error = check<int>(); / *error */
return 0;
}
The error that is get is invalid initialization of reference of type 'int&' from expression of type 'const int'
This:
typedef int& ref;
const ref error;
Doesn't do what you think it does. Consider instead:
typedef int* pointer;
typedef const pointer const_pointer;
The type of const_pointer is int* const, not const int *. That is, when you say const T you're saying "make a type where T is immutable"; so in the previous example, the pointer (not the pointee) is made immutable.
References cannot be made const or volatile. This:
int& const x;
is meaningless, so adding cv-qualifiers to references has no effect.
Therefore, error has the type int&. You cannot assign a const int& to it.
There are other problems in your code. For example, this is certainly wrong:
template<class t>
t const& check()
{
return t(); //return a temporary object
}
What you're doing here is returning a reference to a temporary object which ends its lifetime when the function returns. That is, you get undefined behavior if you use it because there is no object at the referand. This is no better than:
template<class t>
t const& check()
{
T x = T();
return x; // return a local...bang you're dead
}
A better test would be:
template<class T>
T check()
{
return T();
}
The return value of the function is a temporary, so you can still test that you can indeed bind temporaries to constant references.
Your code gives error because the const qualifier in const ref error is just ignored because 8.3.2/1 says
Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef (7.1.3) or of a template type argument(14.3), in which case the cv-qualifiers are ignored.`
So error has type int& not const int& .
It's a very common mistake for English speaking people, because of the way the English grammar works.
I consider it extremely unfortunate that the C++ syntax would allow both:
const int // immutable int
int const // immutable int
to have the same meaning.
It doesn't make it easier, really, and isn't composable since:
const int* // mutable pointer to immutable int
int* const // immutable pointer to mutable int
certainly do NOT have the same meaning.
And this, unfortunately for you, what kicks in here, as #GMan explains.
If you wish to avoid this kind of error in the future, take the habit of qualifying your types (const and volatile) on their right, then you'll be able to treat a typedef as simple text replacement.
To maintain consistency with the Right Left Rule, I prefer to use 'cv' qualifiers like so.
int const x = 2; // x is a const int (by applying Right Left rule)
int const *p = &x; // p is a pinter to const int
In your example, I would write const ref error = check<int>(); like so
ref const error = check<int>(); // parsed as error is a const reference to an integer
As #Prasoon Saurav pointed out, cv qualifiers are ignored when introduced through typedef because as #GMan also says, that cv qualified references are ill-formed.
Therefore the declaration is effectively as below, which of course is an error.
int &error = check<int>();
Check out this for more information.
This is compiled:
typedef const int& ref;
ref error = check<int>();
VC++ compiler gives some explanation of your error: qualifier applied to reference type; ignored. Reference type must be declared as constant, const cannot be applied later.