2011-12-27 52 views
0

我正試圖編寫一個表達式模板,並遇到了一個我不知道如何解決的問題。我讀過C++模板:完整指南,但他們似乎沒有解決這個問題。需要表達式模板中的非常量表達式

作爲一個例子,考慮集合類型set(整數)的表達式模板與標準集運算交集,聯合,否定,異或等等。這些函數都有迭代器的高效實現,所以我希望我的表達式模板類具有類似於迭代器的接口。例如,

class set_expr_set 
{ 
    set::iter i; 

    set_expr_set (const set &s) : i(s) { } 

    operator bool() const { return (bool)i; } 
    void operator ++() { i ++; } 
    int val() { return *i; } 
} 

,然後我表達模板類set_expr_union,等等。現在的問題是,創建對應於表達的對象模板表達都是臨時工,因此常量,而是要評估我需要表達遍歷這些值(調用++val),這些值是非常量。我不能將set::operator = (set_expr &)聲明爲非常量,因爲臨時對象不會綁定非常量參數。我可以拋棄operator =中的常量,但這並不是正確的解決方案。

我是我的例子沒有足夠的細節來使問題清楚,我會很樂意澄清。

編輯:這裏有一些更多的細節。假設set_expr_unionset_expr_intersection也有上述接口:operator ++,valoperator bool。另外,假設我有

template<class T> 
class set_expr 
{ 
    T t; 
    ...; 
} 

其中T是爲了成爲一個set_expr_union等,set_expr還出口t++, val, bool接口。

表達通過各種運算符產生模板對象,例如:

template<class T1, class T2> 
set_expr<set_expr_intersection> 
operator & (const set_expr<T1> &e1, const set_expr<T2> &e2) 
{ 
    return set_expr<set_expr_intersection> (set_expr_intersection (e1.t, e2.t)); 
} 

真的,臨時對應於來自操作者的返回值是問題所在。

現在,考慮

class set 
{ 
    ...; 

    template<class T> 
    set &operator = (const set_expr<T> &e) 
    { 
    clear(); 
    for (; e; e ++) 
     add_element (e.val()); 
    } 
}; 

,我想要的東西使用像set3 = set1 & set2

這是我想寫的那種代碼。

+1

臨時性不必是'const',除非您希望它們是。你能展示一個你正在努力工作的表達的例子嗎? – 2011-12-27 23:12:03

+1

也可以考慮在[Boost.Proto](http://www.boost.org/libs/proto/)上面編寫表達式模板以避免這些問題。 – ildjarn 2011-12-27 23:14:49

+0

這很含糊。臨時並不總是常量。假設'set'是某種容器,比如'std :: set',那麼它也應該有一個非const的迭代器實現。在絕大多數情況下,你不應該像'return(bool)i;'或'const_cast'那樣做。 – AJG85 2011-12-27 23:15:33

回答

1

一個解決方案是讓你的表達式複製構造和賦值(如果它們相對較輕,似乎是這種情況,這應該不是一個大問題)。在集合賦值運算符中,創建集合表達式的副本並遍歷副本。

template<class T> 
set& operator=(const set_expr<T> &e) { 
    clear(); 
    for (set_expr<T> i = e; i; i++) { 
    add_element (i.val()); 
    } 
    return *this; 
} 

如果複製的表達式集原來是太貴了,考慮遷移到C++ 11和move語意讀了。

+0

嗨馬庫斯,感謝您的回覆!這正是我最終做的,通過使'operator ='參數不參考。感謝關於C++ 11移動語義的提示,這聽起來很有用。 – 2011-12-30 15:59:33