Re: [RFA 02/22] Use RAII to save and restore scalars

Pedro Alves
2016-09-30T02:45:55Z

On 09/30/2016 02:17 AM, Pedro Alves wrote:
> On 09/27/2016 09:59 AM, Trevor Saunders wrote:
>
>>> I had hoped that template parameter deduction would work here, but it
>>> did not, and so the patch uses explicit template parameters
>>> everywhere.
>>
>> yeah, you can't deduce template args from a constructor in C++
>
> I don't know whether the trick below is usual,

Looks like it is -- Andrei Alexandrescu's ScopeGuard uses the
same trick:

http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758

Thanks,
Pedro Alves

> but you can work
> around that and end up with no-template-args-in-sight usage
> like this:
>
> void
> foo ()
> {
> scoped_restore scope = make_scoped_restore (&some_global);
>
> ...
> }
>
> You'd do something like this:
>
>
> struct scoped_restore_base {};
>
> template<typename T>
> class scoped_restore_ : public scoped_restore_base
> {
> public:
> ...
> explicit scoped_restore (T *var)
> : saved_var (var),
> saved_value (*var)
> {}
>
> ~scoped_restore ()
> {
> *saved_var = saved_value;
> }
>
> private:
> scoped_restore &operator= (const scoped_restore &rhs);
>
> // The saved variable.
> T *saved_var;
>
> // The saved value.
> T saved_value;
> };
>
> typedef const scoped_restore_base &scoped_restore;
>
> template<class T>
> scoped_restore_<T> make_scoped_restore (T *var)
> {
> return scoped_restore_<T> (var);
> }
>
> The trick is making scoped_restore_ inherit a non-template
> class, and make "scoped_restore" a typedef for a const reference
> to the base class, since a const reference can bind to the
> temporary that is returned by make_scoped_restore, and it
> extends the temporary's lifetime.
>
> While copy elision / RVO makes it so that the temporary returned by
> value from make_scoped_restore is constructed directly in the caller
> instead of constructed and then copied out, you still have to
> provide the copy constructor, instead of "deleting" it as in your
> original patch. Copy elision was optional until C++17, but I
> believe all compilers worth their salt implement it. And if a compiler
> doesn't implement it, it's not a real issue, anyway, the code
> still works.
>
> The downside is that printing a scoped_restore object from
> gdb will just print the reference using the base type, so you
> won't see stored fields.
>
> (gdb) p scope
> $1 = (const scoped_restore) @0x7fffffffd910: {<No data fields>}
>
> To see the object's fields you'd have to downcast it manually, like:
>
> (gdb) p (scoped_restore_<ui_out *>) scope
> $1 = {<scoped_restore_base> = {<No data fields>}, saved_var = 0x601050 <current_uiout>, saved_value = 0x0}
>
> Not sure whether that's an issue.
>
> Thanks,
> Pedro Alves
>