2014-02-14 65 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); 
}