[英]how is this sizeof expression evaluated? and why it is called that way?
我在std::optional
实现中遇到了这段代码:
template <class T, class U>
struct is_assignable
{
template <class X, class Y>
constexpr static bool has_assign(...) { return false; }
template <class X, class Y, size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true)) >
// the comma operator is necessary for the cases where operator= returns void
constexpr static bool has_assign(bool) { return true; }
constexpr static bool value = has_assign<T, U>(true);
};
我无法理解它是如何工作或如何评估的部分是size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true))
我知道如果分配操作失败它会回到has_assign的第一个定义,返回false,但我不知道为什么它有, true)
部分。
我使用在assign运算符上返回void的结构进行了一些测试,并删除了sizeof
, true
部分,给出了相同的结果。
原则上,表达式std::declval<X>() = std::declval<Y>()
的类型(即, operator =
涉及的返回类型)可以是任意的,包括不完整的类型或void
。 在这种情况下,SFINAE不会启动,因为表达式是有效的。 但是,您将从将sizeof
应用于不完整类型时收到错误。 (请注意,某些编译器将sizeof(void) == 1
定义为扩展名,但不能普遍依赖)。
在SFINAE表达式之后添加, true
通过丢弃赋值的类型(无论它是什么)来修复此问题,并将sizeof
应用于true
(这是完全有效的)。
正如Barry在评论中所指出的,更直接的方法是在decltype
而不是sizeof
使用赋值sizeof
,如下所示:
template <class X, class Y, class S = decltype(std::declval<X>() = std::declval<Y>()) >
constexpr static bool has_assign(bool) { return true; }
要应用sizeof()
,您需要一个完整的类型。 但是返回完整类型不是可赋值的要求,因此:
sizeof((std::declval<X>() = std::declval<Y>(), true))
~~~~~~~~~~~~~~~~~~ expr ~~~~~~~~~~~~~~~~~~~~~
如果转让的有效期为这两种类型,那么我们sizeof(expr)
,其中的类型expr
是bool
(因为true
)。 因此,如果赋值有效,我们会得到一些实际size
。 否则,替换失败。
但这是编写此代码的一种不必要的神秘方式。 而且,它甚至不正确,因为我可以写一个类似的类型:
struct Evil {
template <class T> Evil operator=(T&& ); // assignable from anything
void operator,(bool); // mwahahaha
};
现在你的sizeof()
仍然不起作用。
相反,更喜欢简单:
class = decltype(std::declval<X>() = std::declval<Y>())
这实现了相同的结果 - 替换失败与否 - 无需关心结果的类型或处理特殊情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.