gpt4 book ai didi

c++ - addressof() 可以实现为 constexpr 函数吗?

转载 作者:IT老高 更新时间:2023-10-28 22:21:52 26 4
gpt4 key购买 nike

我需要写一个 constexpr addressof 函数,但我觉得不可能。有谁知道这是否可能?

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,即使标题 中的许多函数最近已升级为 constexpr。

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

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

想象一下 MyType 重载了 operator&。

最佳答案

正如评论中提到的,您可以检测是否重载 operator&可使用 SFINAE。正如 Potatoswatter 在评论中指出的那样,这些需要进行三项单独的检查:

1) 是否x.operator&()被接受

2) 是否operator&(x)被接受

前两种是用户提供的两种方式operator&可以定义。

3) 是否&x被接受

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

这些检查可以通过检查 sizeof(f(std::declval<T>())) 来实现。 , 其中 f以某种方式重载,使得返回类型取决于 T通过检查。

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 的哪个实现使用:

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用于常量表达式,只要 operator&没有重载。如果它被重载,似乎无法以可用于常量表达式的形式可靠地获取地址。

请注意,GCC 4.7 拒绝使用此 addressof它应该工作的实现案例。 GCC 4.8 和更高版本可以正常工作,clang 也是如此。

我使用了 addressof 的单一实现在我的答案的早期版本中转发到辅助函数,但我最近意识到这不是一个好主意,因为如果 addressof<X> 很容易导致 ODR 违规用于某些类X在多个翻译单元中,其中一些 X已定义,其中一些 X不完整。拥有两个独立的函数可以避免这个问题。

剩下的唯一问题是,如果 addressof<X>,它可能会失败。在 X 的定义之前的翻译单元中使用的定制operator& .希望这种情况足够罕见,以至于在实践中不会出现问题。

合理示例的测试用例:

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;

关于c++ - addressof() 可以实现为 constexpr 函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14863422/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com