2014-02-14 61 views
1

我經常發現自己處於想要獲取指向容器中的對象的指針(如果存在),或者如果不是,則爲nullptr。這導致我需要檢查迭代器是否等於std::end(container),然後取消引用迭代器或返回nullptrC++將迭代器轉換爲指針(並將end()轉換爲nullptr)

例如:

std::map<int, bar> container; 
... 
// case 1: passing to a function that needs a pointer... 
auto iter = container.find(5); 
foo(iter != container.end() ? &(*iter) : nullptr); 

// case 2: executing a branch if the pointer is valid 
auto iter = container.find(5); 
if (auto ptr = iter != container.end() ? &(*iter) : nullptr) 
{ 
    // do stuff 
} 

我恨我如何能在一個行,因爲我們需要引用iter兩次,這導致在引進iter到父範圍不會做這些。

一種方式做到這一點,而無需iter父範圍將使用lambda我猜(未經測試):

if (auto ptr = [&](container::iterator i){ return i == container.end() ? nullptr : &(*i); }(container.find(5))) 
{ 
    //do stuff 
} 

但似乎非常繁瑣。有沒有其他有效的方法來做到這一點(使用find的單一電話)?

回答

1
template<class C, class L> 
decltype(&*std::begin(std::declval<C>())) 
as_ptr(C&&c, L&&f){ 
    auto it = std::forward<L>(f)(); 
    if (it==c.end()) return nullptr; 
    return &*it; 
} 

auto* p = as_ptr(vec, [&]{return vec.find(x);}); 

完全adl上begin會更好。

這使您可以在容器上運行任何算法,並獲取指針或null。

+0

難道不是'std :: forward (f)'太多了?無論我們將它看作是左值還是右值,調用「f」是否真的發生了變化?畢竟,我們不會將'f'傳遞給另一個可能需要'T &&'的函數。 – Zeta

+0

我可以重寫'operator()&&'而不是'operator()' - 它很少完成,但是在編寫通用代碼時,請儘可能完整地編寫它。作爲一個例子,未來的C++可以優化'&&'lambda表達式的調用來移動隱式返回的捕獲狀態。 – Yakk

+0

啊,是的。我雖然關於'member_methods()&&',但顯然我在凌晨3點太累了以記住'operator()'。 – Zeta

0

簡單的getter怎麼樣?

template<class Container> 
auto get_value(Container& c, typename Container::key_type x) 
    -> decltype(*c.begin())* 
{ 
    auto it = c.find(x); 

    return (it != c.end()) 
     ? &*it; 
     : nullptr; 
} 
1

我會使用一些模板函數,一個用於容器key_type(因此find成員函數),和另外一個,以便找到它們value_type的值,使用std::find

template <class Container> 
typename Container::pointer find_as_ptr(Container& ctn, typename Container::key_type const & key){ 
    auto iter = ctn.find(key); 
    return iter == ctn.end() ? nullptr : &(*iter); 
} 

template <class Container> 
typename Container::pointer find_as_ptr(Container& ctn, typename Container::value_type const & val){ 
    auto iter = std::find(ctn.begin(), ctn.end(), val); 
    return iter == ctn.end() ? nullptr : &(*iter); 
}