2016-08-01 210 views
2

我正在研究一個小型圖書館,我需要做的事情之一是將訪問者應用於某些數據並返回結果。爲什麼`std :: common_type_t <std :: ostream&,std :: ostream&>`等於`std :: ostream`而不是`std :: ostream&`?

在一些較舊的C++代碼中,訪問者預計會聲明一個typedef return_type。例如,boost::static_visitor這樣做。

在較新的代碼中,所有這些訪問者都被棄用。在C++ 14中,您通常可以使用decltype(auto),但我正在嘗試使用類似std::common_type的東西來做到這一點,以便我可以在C++ 11中執行此操作。

我試着簡單地將std::common_type的示例實現反向移植到C++ 11並使用它來計算返回類型。

但是在cppreference.com

#include <ostream> 
#include <type_traits> 

// decay_t backport 

template <typename T> 
using decay_t = typename std::decay<T>::type; 

// common_type backport 

template <typename T, typename... Ts> 
struct common_type; 

template <typename T> 
struct common_type<T> { 
    using type = decay_t<T>; 
}; 

template <typename T1, typename T2> 
struct common_type<T1, T2> { 
    using type = decay_t<decltype(true ? std::declval<T1>() : std::declval<T2>())>; 
}; 

// TODO: Is this needed? 
/* 
template <typename T> 
struct common_type<T, T> { 
    using type = T; 
}; 
*/ 

template <typename T1, typename T2, typename T3, typename... Ts> 
struct common_type<T1, T2, T3, Ts...> { 
    using type = typename common_type<typename common_type<T1, T2>::type, T3, Ts...>::type; 
}; 

template <typename T, typename... Ts> 
using common_type_t = typename common_type<T, Ts...>::type; 

// static_assert(std::is_same<common_type_t<std::ostream &, std::ostream &>, std::ostream &>::value, "This is what I expected!"); 
static_assert(std::is_same<common_type_t<std::ostream &, std::ostream &>, std::ostream>::value, "Hmm..."); 

int main() {} 

使用「可能實現」的時候什麼「應該」的std::common_type_t<std::ostream&, std::ostream&>的結果是我得到一些意想不到的結果?它應該不是std::ostream &?如果沒有,那麼爲什麼gcc 5.4.0clang 3.8.0認爲它是std::ostream

注意:當我在C++ 14中使用「真實」std::common_type_t時,我仍然得到std::ostream而不是std::ostream &

正在專精std::common_type這樣std::common_type_t<T, T>總是T有效的方法嗎?它似乎在我的程序中運行良好,但感覺像是一個黑客。

+2

相關:http://stackoverflow.com/q/21975812/2069064,但是'common_type'不會給你引用,因爲悲傷的臉。 – Barry

+0

謝謝...所以我想我不應該在那裏使用'std :: declval'?我應該使用'decltype(true?std :: forward (std :: declval ()):std :: forward (std :: declval ())''?我想這實際上很棘手... –

回答

2

有關common_type的歷史相關討論請參見this question,以及爲什麼它實際上沒有提供參考。

是專精std::common_type因此std::common_type_t<T, T>永遠是一個有效的方法嗎?

我假定你的意思專業實施common_type(因爲你不能專注另一個)。不,這還不夠。您可能想要common_type<Base&, Derived&>Base&,但該實例化不會經過您的專業化。

你真正想要的是而不是使用decaydecay在那裏的原因是在某些情況下刪除了declval提供的令人驚訝的右值引用。但要保持左值參考 - 所以只需添加自己的類型特點:

template <class T> 
using common_decay_t = std::conditional_t< 
    std::is_lvalue_reference<T>::value, 
    T, 
    std::remove_reference_t<T>>; 

並使用它的正常decay

+0

好吧,我會用這個實驗中,謝謝各位大大 –

+0

我想我這個版本的工作就目前而言,雖然標誌着你的答案是正確的:使用mini_decay_t = conditional_t < 的std :: is_lvalue_reference ::值'模板 , T, decay_t >; ' –

相關問題