以下是std::is_assignable的实现,我花了几个小时试图了解如何静态地找出模板化对象的类型但不能。
在标准is_assignable
状态中,分配的双方都转换为std::add_rvalue_reference<T>::type
。我没有得到那个句子,也没看到std::add_rvalue_reference<T>::type
如何用来预测对象的类型。
有人能够给我一个简单的解释,我可以用它来了解std :: is_assignable的工作原理吗?
答案 0 :(得分:6)
这里有相同的代码,其中包含了一些词法混淆:
1043 template <typename Tp, typename Up>
1044 class is_assignable_helper
1046 {
1047 template <typename Tp1, typename Up1>
1048 static decltype(declval<Tp1>() = declval<Up1>(), one())
1049 test(int);
1050
1051 template<typename, typename>
1052 static two test(...);
1053
1054 public:
1055 static constexpr bool value = sizeof(test<Tp, Up>(0)) == 1;
1056 };
本课程使用SFINAE来完成肮脏的工作。也就是说,变量value
的值将取决于基于重载决策选择的test()
函数。一个重载采用整数,另一个采用C variadic参数(由省略号指定)。如果在第一次重载时发生替换失败,则将选择第二次重载。
如果替换失败发生,则它将来自表达式declval<Tp1>() = declval<Up1>()
。 declval<T>()
是一个函数声明,&#34;返回&#34;类型std::add_rvalue_reference<T>::type
的值。此函数主要用于未评估的上下文,如decltype()
,sizeof()
,noexcept()
等,以便在不显式调用构造函数的情况下获取类型的实例(因为该类型可能没有一个可访问的构造函数)。如果您想知道为什么add_rvalue_reference
是所选择的返回类型,请参阅this post。
获得该类型的实例后,可以在这些实例上调用成员/非成员函数。使用的成员函数是operator=()
。如果某个类没有赋值运算符(或具有不可访问的运算符),则会发生替换失败。将改为选择test()
的后备(可变参数)版本。
参数类型(int
vs ...
)之间存在差异的原因是因为...
具有最低的转换排名,并且它充当了最后的手段&#34;用于重载分辨率。我们不能将参数留空,否则我们会收到重新声明错误。
至于test
的返回类型 - 如果替换失败不发生(类型Up
的值可以分配给类型{{1}的值然后Tp
返回一个表示成功的类型。如果确实发生了替换失败,则选择返回指示失败的类型的回退版本。这些类型通过检查其大小来区分。我们通过与test()
进行比较来检查是否成功。