Domanda

È la mia comprensione che i modelli di espressione si romperanno su interrogati in base a C ++ 11, poiché for (auto x : expr) ha un auto&& __range = expr implicito in esso, e questo comporterà riferimenti penzoli.

C'è un modo in cui creare classi di modello di espressione in modo che si comportino correttamente con le interrogazioni a distanza per, o per lo meno gettare un errore di compilazione?

Fondamentalmente, vorrei impedire la possibilità che i modelli di espressione abbiano correttamente compilare, ma falliscono in fase di esecuzione a causa di riferimenti pendenti.Non mi dispiace dover avvolgere i modelli di espressione in qualcosa prima di usarli in una basata a distanza per, purché non ci siano errori di runtime silenziosi se l'utente dimentica di avvolgere i modelli di espressione.

È stato utile?

Soluzione

There's a few options I can think of, each with their own ugliness.

One obvious option is to use pointers (probably unique_ptr) instead of references. Of course, in order for this to work, it either requires allocation from the heap, or custom allocators. I think with a good allocator, this approach has some merits. Then again, the operator overloading would just get nasty.

Another approach is to store sub-expressions by value instead of by const reference. The efficiency of this approach is very compiler-dependant, but since you're basically dealing with a bunch of temporaries, I would imagine that modern compilers can optimize away the copies (or at least, a lot of the copies).

The last approach allows you to keep the same structure to your code, but forces the user to evaluate the expression. It requires that you have only one iterable type, which is the underlying type of the expression (say, std::vector<int>). None of the expression classes should have begin and end methods or functions defined for them, but should just be convertible to the underlying type. This way, code like for(auto x : expr) will fail at compile-time (since expr is not iterable), but writing for(auto x : static_cast<vector<int>>(expr)) works because the expression is already evaluated.

If you were hoping to use range-based for loops to implement expression template operations, then you can provide private or protected begin and end methods in your expression template classes. Just make sure each template class can access the begin and end methods of the other template classes. It should be okay in this context since the expression template is a parameter to the function, so you won't have to worry about dangling references when writing the loop within that function.

Altri suggerimenti

There's generally nothing you can do about this. If you give an expression as the range, it must resolve to something that will be valid after the initialization of the for statement. And there's no way to detect at compile-time that any particular type was deduced by auto.

It would be better to make your expression system more move-based, so that it doesn't have to hold references. That will yield much safer results with auto than trying to store references to potentially dead things. If the copying for non-movable types troubles you, then just live with it.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top