If you were to look at this code,
int x = 0;
function(x);
std::cout << x << \'\\n\';
you would not be able to verify through any me
Many (most) IDE's help you with this problem by displaying the function/method prototype(s) once they figure out which function you are calling.
Some people insist that the correct way to pass mutable object is to use a pointer. That is, you would pass
Lowercase(&str);
... and Lowercase()
would, obviously, be implemented to take a pointer. That approach may suit your needs.
I want to mention, however, that this is not what I would do! Instead, the approach I favor is to use appropriate names instead. For example,
inplace_lowercase(str);
pretty much says what it is going to do. Clearly, inplace_lowercase()
would actually be an algorithm and with a bit of magic could be reasonably be called as
inplace_lowercase(str.begin() + 1, str.end());
as well.
Here are a few reasons why I don't like passing arguments by pointer and/or why I don't believe in an explicit indication of how the argument is passed:
T const*
.If you use MS VC++ then maybe it will be useful information about source-code annotation language (SAL) http://msdn.microsoft.com/ru-ru/library/hh916383.aspx
This is C++: the lack of in
and out
parameters doesn't mean the language is deficient, it means you need to implement what other languages would do as a language feature as a library.
Create two template
classes and functions.
in_param<T>
is a wrapper around a T const&
, whilie io_param<T>
is a wrapper around a T&
reference. You construct them by calling helper functions in
and io
.
Inside, they behave like references (via overloading).
Outside, the caller must call in
or io
on the argument, marking it up at the call site.
out
is trickier: inside the fumction, only assignment is legal. Ideally we would not even construct it: an emplace
method might help.
However, the caller needs some channel to know if the parameter was constructed or not.
What I would do is out_param
only has operator=
, and it assigns. out
wraps something into an out_param
. If you want delayed constructuon, use optional
inside the out param, which gets close. Maybe out_param
also has emplace
, which usually just assigns, but if the tyoe wrapped has emplace
calls it instead?
template<typename T>
struct in_param : std::reference_wrapper<T const> {
explicit in_param( T const& t ):std::reference_wrapper<T const>(t) {}
in_param( in_param<T>&& o ):std::reference_wrapper<T const>(std::move(o)) {}
void operator=( in_param<T> const& o ) = delete;
};
template<typename T>
struct io_param : std::reference_wrapper<T> {
explicit io_param( T& t ):std::reference_wrapper<T>(t) {}
io_param( io_param<T>&& o ):std::reference_wrapper<T>(std::move(o)) {}
};
template<typename T>
in_param< T > in( T const& t ) { return in_param<T>(t); }
template<typename T>
io_param< T > io( T& t ) { return io_param<T>(t); }
template<typename T>
struct out_param {
private:
T& t;
public:
out_param( T& t_ ):t(t_) {}
out_param( out_param<T>&& o ):t(o.t) {}
void operator=( out_param<T> const& o ) = delete;
void operator=( out_param<T> && o ) = delete;
void operator=( out_param<T> & o ) = delete;
void operator=( out_param<T> && o ) = delete;
template<typename U>
out_param<T>& operator=( U&& u ) {
t = std::forward<U>(u);
return *this;
}
// to improve, test if `t` has an `emplace` method. If it does not,
// instead do t = T( std::forward<Us>(us)... ). (I'd use tag dispatching
// to call one of two methods)
template<typename... Us>
void emplace( Us&&... us ) {
t.emplace( std::forward<Us>(us)... );
}
};
template<typename T>
out_param<T> out( T& t ) { return out_param<T>(t); }
or something like the above.
You now get syntax like:
void do_stuff( int x, in_param<expensive> y, io_param<something> z, out_param<double> d );
int main() {
expensive a;
something b;
double d;
do_stuff( 7, in(a), io(b), out(d) );
}
and failure to call in
, io
or out
at the call site results in compile time errors. Plus, out_param
makes it quite difficult to accidentally read the state of the out
variable within the function, producing some very nice documentation at the call site.
I think it's something useless to notify (by language nonetheless [1]). The only needed question is : "Is my object is semantically modified ?", and so :
[1] A static analyzer could do it for its purposes.
[2] If you miss, the compiler would warn you anyway.
I'm not sure I understand your requirements completely, but maybe this is something you can use:
template<typename T>
void foo( T ) { static_assert( sizeof(T)==0, "foo() requires a std::ref" ); }
void foo( std::reference_wrapper<int> t )
{
// modify i here via t.get() or other means of std::reference_wrapper
}
int main()
{
int i = 42;
// foo( i ); // does not compile, static_assert fires
foo( std::ref( i ) ); // explicit std::ref visible on the caller's side
}