2017-08-08 52 views
2

说我有一个功能f()类型:是否可以使用统一的取消引用语法?

struct A { void f() {} }; 

和两个向量:(指针的傻数量只是为了戏剧效果)

std::vector<A*>  x; 
std::vector<A*******> y; 

我寻找能够写作的方式:

deep_deref(std::begin(x)).f(); 
deep_deref(std::begin(y)).f(); 

换句话说,我要的是搭载一台通用的,多层次,智能解除引用功能的统一的解引用语法(或其他的东西会允许统一取消引用语法)deep_deref()即会取消引用传递给它,那么对象从取消引用所获得的对象,那么接下来,依此类推,直到它到达一个非dereferencable对象,此时它会返回最终目标。

注意,沿着解引用的这条道路有可能撒谎各种dereferencable对象:指针,迭代器,智能指针,等等 - 任何dereferencable。

是这样的可能吗? (假设我有is_dereferencable。)

+0

不能你写使用['标准:: is_pointer'(HTTP一个_type traits_基于递归模板:// en.cppreference.com/w/cpp/types/is_pointer)还是这样? – user0042

+1

@ user0042'std :: is_pointer 'struct只会检查'T'是否是*指针*,而不是迭代器,智能指针等。 –

+0

您是否在寻找[std :: invoke](http:// en .cppreference.com /瓦特/ CPP /实用程序/功能/调用)? –

回答

1

使用std::decay通过取消引用和删除CV限定符来创建can_dereference函数,这可以完成。

链接到here的答案是一个完整的实施以及一个实时样本。

我最初发布这个作为一个评论,但认为答案会是更好地帮助人们寻找

+0

也感谢所有提交他们的版本的人。 –

1
template < typename T, bool isDeref = is_dereferenceable<T>::value > 
struct deref_ 
{ 
    static T& call(T & t) { return t; } 
}; 

template < typename T > 
struct deref_<T,true> 
{ 
    static decltype(*declval<T>()) call(T & t) { return deref_<decltype(*t)>::call(*t); } 
}; 

template < typename T > 
auto deref(T & t) { return deref_<T>::call(t); } 

这是未经测试和不完整的。你应该使用& &和转发和所有。很多清理和重新排序做...

我还问身边有像这样的智慧。

+0

C++ 11记住。 – Yakk

0

一些样板:

namespace details { 
    template<template<class...>class, class, class...> 
    struct can_apply:std::false_type{}; 
    template<class...>struct voider{using type=void;}; 
    template<class...Ts>using void_t=typename voider<Ts...>::type; 
    template<template<class...>class Z, class... Ts> 
    struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{}; 

} templateclass Z,类... TS> 使用can_apply =细节:: can_apply; 一个特征,以确定是否应*

template<class T> 
using unary_star_r = decltype(*std::declval<T>()); 

template<class T> 
using can_unary_star = can_apply<unary_star_r, T>; 

dispatch在编译的时候把他们之间的两个参数和选秀权:

template<bool /*false*/> 
struct dispatch_t { 
    template<class T, class F> 
    F operator()(T, F f)const{ return std::move(f); } 
}; 
template<> 
struct dispatch_t<true> { 
    template<class T, class F> 
    T operator()(T t, F)const{ return std::move(t); } 
}; 

#define RETURNS(...) \ 
    noexcept(noexcept(__VA_ARGS__))\ 
    ->decltype(__VA_ARGS__)\ 
    { return __VA_ARGS__; } 
template<bool b, class T, class F> 
auto 
dispatch(T t, F f) 
RETURNS(dispatch_t<b>{}(std::move(t), std::move(f))) 

我们几乎完成了...

现在我们的工作。我们写这代表解引用类型,什么都不做,也许做任何函数对象:

struct maybe_deref_t; 
struct do_deref_t; 
struct identity_t { 
    template<class T> 
    T operator()(T&& t)const { return std::forward<T>(t); } 
}; 

struct do_deref_t { 
    template<class T> 
    auto operator()(T&& t)const 
    RETURNS(maybe_deref_t{}(*std::forward<T>(t))) 
}; 

这里的工作:

struct maybe_deref_t { 
    template<class T> 
    auto operator()(T&& t)const 
    RETURNS(
    dispatch< can_unary_star<T>::value >(
     do_deref_t{}, 
     identity_t{} 
    )(
     std::forward<T>(t) 
    ) 
) 
}; 

和更好的语法帮助:

template<class T> 
auto maybe_deref(T&& t) 
RETURNS(maybe_deref_t{}(std::forward<T>(t))) 

测试代码:

int main() { 
    auto bob = new int*(new int(7)); // or 0 or whatever 
    std::cout << maybe_deref(bob) << "\n"; 
} 

live example

我最初是用C++ 14风格编写的,然后将它翻译回C++ 11。在C++ 14中它更清洁。

0

对于任何人谁可以使用较新的C++版本:

#include <utility> 

namespace detail 
{ 
struct Rank_0 {}; 
struct Rank_1 : Rank_0{}; // disambiguate overloads 

template <class T, std::void_t<decltype(*std::declval<T>())>* = nullptr> 
decltype(auto) deep_deref_impl(T& obj, Rank_1) 
{ 
    return deep_deref_impl(*obj, Rank_1{}); 
} 

template <class T> 
decltype(auto) deep_deref_impl(T& obj, Rank_0) 
{ 
    return obj; 
} 
} 

template <class T> 
decltype(auto) deep_deref(T& obj) 
{ 
    return detail::deep_deref_impl(obj, detail::Rank_1{}); 
} 
auto test() 
{ 
    int a = 24; 
    int* p1 = &a; 
    int** p2 = &p1; 
    int*** p3 = &p2; 
    int**** p4 = &p3; 

    deep_deref(a) += 5; 
    deep_deref(p4) += 11; 

    return a; // 40 
} 

godbolt

0

我喜欢让事情变得简单检查它......我会实现它像这样:

template <class T> 
auto deep_deref_impl(T&& t, int) -> decltype(deep_deref_impl(*t, int{})) { 
    return deep_deref_impl(*t, int{}); 
} 

template <class T> 
T &deep_deref_impl(T&& t, ...) { 
    return t; 
} 

template <class T> 
auto deep_deref(T&& t) -> decltype(deep_deref_impl(std::forward<T>(t), int{})) { 
    return deep_deref_impl(std::forward<T>(t), int{}); 
} 

[live demo]

相关问题