2013-03-12 71 views
5

我正在尋找一種方式來配製具有類:轉換STL容器<T *>集裝箱<T const *>

  • 使用最大「常量性」指針
  • 但其中的STL容器的接口內部變異的尖-to對象
  • 相比於一個非const模擬

理想的情況下沒有額外的運行時開銷,該解決方案將彙編沒有分機ra代碼與非const版本的比較,因爲const/non-const-ness只是幫助程序員在這裏。

這裏是我試過到目前爲止:

#include <list> 
#include <algorithm> 

using namespace std; 
typedef int T; 

class C 
{ 
public: 
    // Elements pointed to are mutable, list is not, 'this' is not - compiles OK 
    list<T *> const & get_t_list() const { return t_list_; } 

    // Neither elements nor list nor' this' are mutable - doesn't compile 
    list<T const *> const & get_t_list2() const { return t_list_; } 

    // Sanity check: T const * is the problem - doesn't compile 
    list<T const *> & get_t_list3() { return t_list_; } 

    // Elements pointed to are immutable, 'this' and this->t_list_ are 
    // also immutable - Compiles OK, but actually burns some CPU cycles 
    list<T const *> get_t_list4() const { 
     return list<T const *>(t_list_.begin() , t_list_.end()); 
    } 

private: 
    list<T *> t_list_; 
}; 

如果沒有解決類型轉換,我想就如何配製具有描述的屬性的類其他建議。

+0

'T const'不只是簡單地轉換爲'T',你必須使用'const_cast',但這很醜陋,違反了const的要點。 – 2013-03-12 11:27:57

+0

@Tony我想將'T'轉換爲'T const',這通常是可能的。以下編譯:'int x = 2; int const * x_ptr =&x;' – SimonD 2013-03-12 11:39:54

+0

不同的模板專業化是不相關的,它們是有效的不同類型。 – Xeo 2013-03-12 11:42:40

回答

7

讓我們假設您暫時可以將list<T*>&轉換爲list<T const *>&。現在考慮下面的代碼:

list<char*> a; 
list<char const*>& b = a; 

b.push_back("foo"); 

a.front()[0] = 'x'; // oops mutating const data 

這是一個與轉換T**T const**同樣的概念問題。

如果您想要提供對基礎數據的只讀訪問,則需要提供一些自定義視圖,可能使用自定義迭代器。

像下面這樣。

template <typename It> 
class const_const_iterator { 
private: 
    using underlying_value_type = typename std::iterator_traits<It>::value_type; 

    static_assert(std::is_pointer<underlying_value_type>(), 
        "must be an iterator to a pointer"); 

    using pointerless_value_type = typename std::remove_pointer<underlying_value_type>::type; 

public: 
    const_const_iterator(It it) : it(it) {} 

    using value_type = pointerless_value_type const*; 

    value_type operator*() const { 
     return *it; // *it is a T*, but we return a T const*, 
        // converted implicitly 
        // also note that it is not assignable 
    } 

    // rest of iterator implementation here 
    // boost::iterator_facade may be of help 

private: 
    It it; 
}; 

template <typename Container> 
class const_const_view { 
private: 
    using container_iterator = typename Container::iterator; 

public: 
    using const_iterator = const_const_iterator<container_iterator>; 
    using iterator = const_iterator; 

    const_const_view(Container const& container) : container(&container) {} 

    const_iterator begin() const { return iterator(container->begin()); } 
    const_iterator end() const { return iterator(container->end()); } 

private: 
    Container const* container; 
} 
+0

Wow ...在我的解決方案中有幾個新東西:使用[name] = typename T和static_assert ...這需要什麼版本的標準? (我已經離開了C++一段時間) – SimonD 2013-03-12 12:06:20

+0

他們來自C++ 11。 '使用A = B;'與'typedef B A'相同;';因爲它只是一個風格問題,你可以用typedef替換它。如果條件不符合,'static_assert'會導致編譯錯誤。這對解決方案來說並不是真正必要的,但它有助於提供更好的錯誤信息。你也可以放棄它。 'std :: remove_pointer'也來自C++ 11,但它可以很容易地在沒有C++ 11的情況下實現(https://gist.github.com/rmartinho/5142454)。 – 2013-03-12 12:15:14

+0

理想的解決方案是'編譯',生成與常量代碼相同的彙編代碼。這個解決方案必須使用更多的內存,因爲有一個非零大小的新類。 Indirections可能會被優化掉 - 取決於It :: operator *是否可以內聯...「const_const_iterator」是否可以從'It'私下派生來去除間接和額外內存使用的級別? – SimonD 2013-03-12 19:42:08

1

不要返回容器。返回迭代器。

+1

@nsgulliver - 如果你唯一的工具是錘子,一切看起來都像釘子。回答**正確的問題通常比盲目地回答被問到的問題更好。 – 2013-03-12 14:41:42

+0

你是絕對正確的!然而,爲了激發答案,多提一點細節可能會很棒。 - nsgulliver 4分鐘前 – nsgulliver 2013-03-12 14:49:30

+0

返回比迭代器更多的東西的動機是容器可能有其他有用的功能,比如'size()','operator []','front()'等等。樣板代碼來修補它們。除了寫作乏味之外,一個班級的真正目的很快會在瑣碎的海洋中變得模糊。 – SimonD 2013-03-12 19:45:19

相關問題