简体   繁体   English

这个sizeof表达式如何评估? 为什么这样称呼?

[英]how is this sizeof expression evaluated? and why it is called that way?

I came across with this code in an std::optional implementation : 我在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);
};

The part that I cant understand how it works or how it is evaluated is size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true)) I know that if the assign operation fails it will fall back to the first definition of has_assign that returns false, but i don't know why it has the , true) part. 我无法理解它是如何工作或如何评估的部分是size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true))我知道如果分配操作失败它会回到has_assign的第一个定义,返回false,但我不知道为什么它有, true)部分。

I did some test with structs that returns void on the assign operator and removing the , true part in sizeof gives me the same results. 我使用在assign运算符上返回void的结构进行了一些测试,并删除了sizeof , true部分,给出了相同的结果。

In principle, the type of the expression std::declval<X>() = std::declval<Y>() (that is, the return type of the operator = involved) can be arbitrary, including an incomplete type or void . 原则上,表达式std::declval<X>() = std::declval<Y>()的类型(即, operator =涉及的返回类型)可以是任意的,包括不完整的类型或void In such case, SFINAE wouldn't kick in, since the expression is valid. 在这种情况下,SFINAE不会启动,因为表达式是有效的。 However, you'd then get an error from applying sizeof to an incomplete type. 但是,您将从将sizeof应用于不完整类型时收到错误。 (Note that some compilers define sizeof(void) == 1 as an extension, but that cannot be universally relied upon). (请注意,某些编译器将sizeof(void) == 1定义为扩展名,但不能普遍依赖)。

Adding , true after the SFINAE expression fixes this by discarding the type of the assignment (whatever it is), and applying sizeof to true instead (which is perfectly valid). 在SFINAE表达式之后添加, true通过丢弃赋值的类型(无论它是什么)来修复此问题,并将sizeof应用于true (这是完全有效的)。

As indicated by Barry in the comments, a more direct approach would be to use the type of the assignment in decltype instead of in sizeof , like this: 正如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; }

In order to apply sizeof() , you need a complete type. 要应用sizeof() ,您需要一个完整的类型。 But returning a complete type isn't a requirement of assignability, hence: 但是返回完整类型不是可赋值的要求,因此:

sizeof((std::declval<X>() = std::declval<Y>(), true))
       ~~~~~~~~~~~~~~~~~~ expr ~~~~~~~~~~~~~~~~~~~~~

if the assignment is valid for those two types, then we have sizeof(expr) where the type of expr is bool (because true ). 如果转让的有效期为这两种类型,那么我们sizeof(expr) ,其中的类型exprbool (因为true )。 So if the assignment is valid, we get some real size . 因此,如果赋值有效,我们会得到一些实际size Otherwise, substitution failure. 否则,替换失败。


But this is an unnecessarily cryptic way of writing this code. 但这是编写此代码的一种不必要的神秘方式。 Moreover, it's not even correct because I could write a type like: 而且,它甚至不正确,因为我可以写一个类似的类型:

struct Evil {
    template <class T> Evil operator=(T&& ); // assignable from anything
    void operator,(bool);                    // mwahahaha
};

and now your sizeof() still doesn't work. 现在你的sizeof()仍然不起作用。

Instead, prefer simply: 相反,更喜欢简单:

class = decltype(std::declval<X>() = std::declval<Y>())

This accomplishes the same result - either substitution failure or not - without needed to care at all about what the type of the result is or to handle special cases. 这实现了相同的结果 - 替换失败与否 - 无需关心结果的类型或处理特殊情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM