2017-08-08 51 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]

相關問題