2016-08-01 211 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 >; ' –

相关问题