大家好,欢迎来到IT知识分享网。
标准库中std::void_t的实现如下:
template<typename...>
using void_t = void;
void_t主要是在模板偏特化中使用,但这一实现,在libstdc++、libc++和MSVC的STL中是存在bug的,这个bug导致它忽略了模板别名中未使用的模板参数,有时候并没有引起替换失败。这个bug已被记录在:
http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
例如:
struct A {
using one = int;
};
struct B {
using two = float;
};
template <typename T,
std::void_t<typename std::decay_t<T>::one>* = nullptr>
void foo(T&&) { }
template <typename T,
std::void_t<typename std::decay_t<T>::two>* = nullptr>
void foo(T&&) { }
int main()
{
foo(A{}); // error: redefinition of ‘template<class T, std::void_t<typename std::decay<_Tp>::type::two>* <anonymous> > void foo(T&&)’
}
第二个foo()将被认为是一个重新定义,因为它与第一个冲突;void_t不会导致替换失败–模板类型被忽略。
folly中实现了自己的void_t,用以修复这一bug,位于:
folly/Traits.h
代码分析
改进方式是,用如下实现替换:
namespace traits_detail {
template <class T, class...>
struct type_t_ {
using type = T;
};
} // namespace traits_detail
template <class T, class... Ts>
using type_t = typename traits_detail::type_t_<T, Ts...>::type;
template <class... Ts>
using void_t = type_t<void, Ts...>;
其中type_t用来获取模板的第一个模板参数。
测试
namespace traits_detail {
template <class T, class...>
struct type_t_ {
using type = T;
};
} // namespace traits_detail
template <class T, class... Ts>
using type_t = typename traits_detail::type_t_<T, Ts...>::type;
template <class... Ts>
using void_t = type_t<void, Ts...>;
struct A
{
using one = int;
};
struct B
{
using two = float;
};
template <typename T,
void_t<typename std::decay_t<T>::one>* = nullptr>
void
foo(T&&)
{
std::cout << "one" << std::endl;
}
template <typename T,
void_t<typename std::decay_t<T>::two>* = nullptr>
void
foo(T&&)
{
std::cout << "two" << std::endl;
}
int
main()
{
foo(A{});
foo(B{});
}
输出:
one
two
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/60688.html