The stock example of a reference-qualified member function seems to be something like this:
#include <stdio.h>
#include <stdexcept>
#include <string>
// Easy access to literals
using namespace std::literals;
// File wrapper
class File {
private:
// The wrapped file
FILE *_file;
public:
File(const char *name) :
_file(fopen(name, "r")) {
// unable to open the file?
if (!_file) throw std::runtime_error{ "Unable to open file: "s + name };
}
~File() {
fclose(_file);
}
// Convert to the underlying wrapped file
operator FILE *() & {
return _file;
}
// TODO: Member functions for working with the file
};
This works well. It is not possible to retrieve the underlying FILE pointer from an unnamed temporary directly. However, if we make the casting operator also const-qualified, this no longer seems to work.
Different compilers simply swallow it without complaint even though it's a terribly useful idea. Take, for example the std::string::c_str() member function. You feel it should be reference-qualified (because otherwise you have an invalid pointer) yet it isn't.
Is this a hole in the C++11 standard? Am I missing something here?
The const keyword can be used as a qualifier when declaring objects, types, or member functions. When qualifying an object, using const means that the object cannot be the target of an assignment, and you cannot call any of its non-const member functions.
The const member functions are the functions which are declared as constant in the program. The object called by these functions cannot be modified. It is recommended to use const keyword so that accidental changes to object are avoided. A const member function can be called by any type of object.
Const Reference to a pointer is a non-modifiable value that's used same as a const pointer. Here we get a compile-time error as it is a const reference to a pointer thus we are not allowed to reassign it.
A constant member function can't modify any non-static data members or call any member functions that aren't constant. To declare a constant member function, place the const keyword after the closing parenthesis of the argument list. The const keyword is required in both the declaration and the definition.
A temporary can be bound to a const&
qualified object and the ref-qualifier effectively qualifies the implicitly passed object (*this
). If you want to prevent calls on temporaries but allow lvalues, you can = delete
the rvalue reference overload and implement the lvalue version. Using const
qualified reference qualifiers for both operators requires just one implemented and one = delete
d implementation:
class File {
// ...
FILE* _file;
public:
operator FILE*() const&& = delete;
operator FILE*() const& { return this->_file; }
// ...
};
The net-effect is that you can use the conversion only for objects to which you go an lvalue:
int main() {
File f;
File const cf{};
FILE* fp = f; // OK
FILE* cfp = cf; // OK
FILE* tfp = File(); // ERROR: conversion is deleted
FILE* mfp = std::move(cf); // ERROR: conversion is deleted
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With