可以将addressof()实现为constexpr函数? [英] Can addressof() be implemented as constexpr function?

查看:140
本文介绍了可以将addressof()实现为constexpr函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要写一个constexpr addressof函数,但我发现它不可能。有没有人知道这是否可能?

I need to write a constexpr addressof function, but I find it impossible. Does anyone know if this is possible?

参考实现在 cppreference.com

template< class T >
T* addressof(T& arg) 
{
  return reinterpret_cast<T*>(
           &const_cast<char&>(
              reinterpret_cast<const volatile char&>(arg)
           )
         );
}

使用reinterpret_cast(类似于GCC实现),所以它不会。我可以看到,最新的C ++标准草案, N3485 也不需要addressof()是constexpr,即使许多函数形成头< utility> have ben最近升级到constexpr。

uses reinterpret_cast (similarly to GCC implementation), so it will not do. I can see that the latest C++ Standard draft, N3485 also does not require that addressof() be constexpr even though lots of functions form header <utility> have ben recently upgraded to constexpr.

一个可能的,虽然不是很有说服力或有用的用例:

A possible, although not very convincing or useful use-case for it would be:

constexpr MyType m;
constexpr MyType const* p = &m;           // this works today
constexpr MyType const* p = addressof(m); // this is my question



假设MyType有重载的operator&。

Imagine that MyType has overloaded operator&.

推荐答案

如注释中所述,您可以使用SFINAE检测是否可以使用重载的运算符& 。正如Potatoswatter在评论中指出的,这些需要三个单独的检查:

As mentioned in the comments, you can detect whether an overloaded operator& is available using SFINAE. And as Potatoswatter points out in the comments, these need to be three separate checks:

1)是否 x.operator& c $ c>已接受

1) whether x.operator&() is accepted

2)是否接受运算符&(x)

前两个是可以定义用户提供的运算符& 的两种方式。

The first two are the two ways a user-provided operator& may be defined.

3)是否接受& x

此第三次检查是必要的,因为 x.operator&()可能会被拒绝,因为运算符& 确实存在,但它是私有的。在这种情况下,& x 无效。

This third check is necessary because x.operator&() may be rejected because operator& does exist, but it is private. In that case, &x is not valid.

这些检查可以通过检查 sizeof(f(std :: declval< T>())),其中 f 取决于 T 是否通过检查。

These checks can be implemented by checking sizeof(f(std::declval<T>())), where f is overloaded in a way such that the return type depends on whether T passes the check.

namespace addressof_helper {
  template <typename T>
  static char (&checkaddressof(...))[1];

  template <typename T>
  static char (&checkaddressof(T &&, typename std::remove_reference<decltype(&std::declval<T &>())>::type * = 0))[2];

  template <typename T>
  static char (&checknonmember(...))[1];

  template <typename T>
  static char (&checknonmember(T &&, typename std::remove_reference<decltype(operator&(std::declval<T &>()))>::type * = 0))[2];

  template <typename T>
  static char (&checkmember(...))[1];

  template <typename T>
  static char (&checkmember(T &&, typename std::remove_reference<decltype(std::declval<T &>().operator&())>::type * = 0))[2];
}

然后可以使用这些帮助函数来选择 addressof 以使用:

You can then use these helper functions to choose which implementation of addressof to use:

template <typename T>
constexpr typename std::enable_if<
  sizeof(addressof_helper::checkaddressof<T>(std::declval<T>())) == 2
  && sizeof(addressof_helper::checknonmember<T>(std::declval<T>())) == 1
  && sizeof(addressof_helper::checkmember<T>(std::declval<T>())) == 1,
  T *>::type addressof(T &t) {
  return &t;
}

template <typename T>
/* no constexpr */ typename std::enable_if<
  sizeof(addressof_helper::checkaddressof<T>(std::declval<T>())) == 1
  || sizeof(addressof_helper::checknonmember<T>(std::declval<T>())) == 2
  || sizeof(addressof_helper::checkmember<T>(std::declval<T>())) == 2,
  T *>::type addressof(T &t) {
  return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(t)));
}

这允许 addressof 只要运算符& 不重载,就可以在常量表达式中使用。如果它是重载的,似乎没有办法可靠地获得可用于常量表达式的形式的地址。

This allows addressof to be used in constant expressions so long as operator& is not overloaded. If it is overloaded, there appears to be no way to reliably get the address in a form that's usable in a constant expression.

请注意,GCC 4.7拒绝使用这个 addressof 实现情况下它应该工作。

Note that GCC 4.7 rejects uses of this addressof implementation cases where it should work. GCC 4.8 and higher work, as does clang.

我使用了转发给帮助器的 addressof 的单个实现函数,但我最近意识到这不是一个好主意,因为如果 addressof< X> 是很容易导致ODR违反用于多个翻译单元中的一些类 X ,其中 X 中的一些被定义, code> X 不完整。有两个单独的函数避免了这个问题。

I used a single implementation of addressof that forwarded to a helper function in an earlier version of my answer, but I was recently made aware that this is not a good idea, as it can easily lead to ODR violations if addressof<X> is used for some class X in multiple translation units, in some of which X is defined, and in some of which X is incomplete. Having two separate functions avoids that problem.

唯一剩下的问题是如果 addressof< X> X 的自定义运算符& 的定义之前用于翻译单元。

The only remaining problem is that it could fail if addressof<X> is used in a translation unit before the definition of X's custom operator&. This should hopefully be rare enough that it's not a problem in practice.

测试用例:

class A { } a;
class B { private: B *operator&(); } b;
class C { C *operator&(); } c;
class D { } d;
D *operator&(D &);
extern class E e;

int main() {
  constexpr A *pa = addressof(a);
  /* no constexpr */ B *pb = addressof(b);
  /* no constexpr */ C *pc = addressof(c);
  /* no constexpr */ D *pd = addressof(d);
  constexpr E *pe = addressof(e);
}

class E { } e;

这篇关于可以将addressof()实现为constexpr函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆