I wrote a little templated RAII-class called SaveGuard
whose constructor makes a copy of the current state of a specified object, and then later on the destructor restores the object from that saved state. That way I can make temporary changes to an object and I am guaranteed that they will be auto-reverted at the end of the current scope (see code below).
That all works fine; my question is this: Is there a way for me to avoid having to explicitly type out the type of the to-be-saved object every time I declare a SaveGuard
? i.e. rather than typing this:
const SaveGuard<std::string> guard(myStr);
I'd prefer to type something like this:
const SaveGuard<> guard(myStr);
Since the type of the object might be rather elaborate, and I might be declaring SaveGuard
objects for it in many places, it would save a lot of typing and declutter my code if I could.
However, trying that yields this error:
temp.cpp:23:17: error: too few template arguments for class template 'SaveGuard'
const SaveGuard<> guard(myStr);
Code follows:
#include <iostream>
#include <string>
/** Convenience class to place on the stack for RAII-swapping of a table out to temporary storage and then back again in the destructor */
template<class T> class SaveGuard
{
public:
SaveGuard(T & saveMe) : _saveMe(saveMe), _tempHolder(saveMe) {/* empty */} // save the current value
~SaveGuard() {_saveMe = _tempHolder;} // restore the saved value
private:
T & _saveMe;
T _tempHolder;
};
int main(int argc, char ** argv)
{
std::string myStr = "foo";
std::cout << "At point A, myStr=" << myStr << std::endl;
{
const SaveGuard<std::string> guard(myStr);
// Make some temporary modifications to myStr
myStr += "bar";
std::cout << "At point B, myStr=" << myStr << std::endl;
}
std::cout << "At point C, myStr=" << myStr << std::endl;
return 0;
}
When run, the code print out this:
At point A, myStr=foo
At point B, myStr=foobar
At point C, myStr=foo
In C++17, you can use class template argument deduction. This requires you to completely omit the template argument list:
SaveGuard guard(myStr); // OK - deduces T as std::string
Before C++17, class template arguments cannot be deduced, so a helper function had to be used instead (std::make_pair
is an example of this). You could write a MakeSaveGuard
function that deduces the template argument from the function argument type (this requires SaveGuard
to be properly movable).