Come ho capito, la radice del problema è che il modello di espressione temporaneo può avere riferimenti/puntatori ad altri temporaries. E usando l'auto & & estendiamo solo la vita del modello di espressione temporaneo, ma non la durata dei temporari a cui ha riferimenti. È giusto?
Per esempio, è this il tuo caso?
#include <iostream>
#include <deque>
#include <algorithm>
#include <utility>
#include <memory>
using namespace std;
deque<bool> pool;
class ExpressionTemp;
class Scalar
{
bool *alive;
friend class ExpressionTemp;
Scalar(const Scalar&);
Scalar &operator=(const Scalar&);
Scalar &operator=(Scalar&&);
public:
Scalar()
{
pool.push_back(true);
alive=&pool.back();
}
Scalar(Scalar &&rhs)
: alive(0)
{
swap(alive,rhs.alive);
}
~Scalar()
{
if(alive)
(*alive)=false;
}
};
class ExpressionTemp
{
bool *operand_alive;
public:
ExpressionTemp(const Scalar &s)
: operand_alive(s.alive)
{
}
void do_job()
{
if(*operand_alive)
cout << "captured operand is alive" << endl;
else
cout << "captured operand is DEAD!" << endl;
}
};
ExpressionTemp expression(const Scalar &s)
{
return {s};
}
int main()
{
{
expression(Scalar()).do_job(); // OK
}
{
Scalar lv;
auto &&rvref=expression(lv);
rvref.do_job(); // OK, lv is still alive
}
{
auto &&rvref=expression(Scalar());
rvref.do_job(); // referencing to dead temporary
}
return 0;
}
In caso affermativo, una delle possibili soluzioni consiste nel creare un tipo speciale di modello di espressione temporaneo che trattiene le risorse spostate dai provvisori.
Ad esempio, controllare l'approccio this (è possibile definire la macro BUG_CASE per ottenere nuovamente il caso di errore).
//#define BUG_CASE
#include <iostream>
#include <deque>
#include <algorithm>
#include <utility>
#include <memory>
using namespace std;
deque<bool> pool;
class ExpressionTemp;
class Scalar
{
bool *alive;
friend class ExpressionTemp;
Scalar(const Scalar&);
Scalar &operator=(const Scalar&);
Scalar &operator=(Scalar&&);
public:
Scalar()
{
pool.push_back(true);
alive=&pool.back();
}
Scalar(Scalar &&rhs)
: alive(0)
{
swap(alive,rhs.alive);
}
~Scalar()
{
if(alive)
(*alive)=false;
}
};
class ExpressionTemp
{
#ifndef BUG_CASE
unique_ptr<Scalar> resource; // can be in separate type
#endif
bool *operand_alive;
public:
ExpressionTemp(const Scalar &s)
: operand_alive(s.alive)
{
}
#ifndef BUG_CASE
ExpressionTemp(Scalar &&s)
: resource(new Scalar(move(s))), operand_alive(resource->alive)
{
}
#endif
void do_job()
{
if(*operand_alive)
cout << "captured operand is alive" << endl;
else
cout << "captured operand is DEAD!" << endl;
}
};
template<typename T>
ExpressionTemp expression(T &&s)
{
return {forward<T>(s)};
}
int main()
{
{
expression(Scalar()).do_job(); // OK, Scalar is moved to temporary
}
{
Scalar lv;
auto &&rvref=expression(lv);
rvref.do_job(); // OK, lv is still alive
}
{
auto &&rvref=expression(Scalar());
rvref.do_job(); // OK, Scalar is moved into rvref
}
return 0;
}
vostri sovraccarichi operatore/funzione può restituire different types, a seconda T & &/const T & argomenti:
#include <iostream>
#include <ostream>
using namespace std;
int test(int&&)
{
return 1;
}
double test(const int&)
{
return 2.5;
};
int main()
{
int t;
cout << test(t) << endl;
cout << test(0) << endl;
return 0;
}
Così, quando il vostro modello di espressione temporanea non hanno risorse spostati da provvisori - è le dimensioni non saranno influenzate.
fonte
2012-10-21 14:14:30
Se si proibisce tale associazione, 'operator + (espressione_template const &, expression_template const &)' non verrebbe compilato neanche. –
@ R.MartinhoFernandes: Perché 'operator +' accetta i suoi argomenti con 'expression_template const &'? Potrei immaginare che 'operator +' possa prendere i suoi argomenti attraverso una sorta di proxy che ancora non permetterebbe che' const reference's sia legato in modo non sicuro ai template di espressione. (Non sto dicendo che sia possibile, ma almeno non è banalmente impossibile). – Mankarse
@Mankarse Non è possibile combinare conversioni implicite e deduzioni del tipo di modello. Poiché per operare è necessario selezionare la deduzione di tipo per 'operator +', gli argomenti devono essere il tipo del modello di espressione. (A meno che non fraintenda cosa intendi per "una sorta di proxy") –