operator&
如评论中所述,您可以使用 SFINAE检测是否有可用的重载。正如 Potatoswatter 在评论中指出的那样,这些需要进行三项单独的检查:
1) 是否x.operator&()
接受
2) 是否operator&(x)
接受
前两种是operator&
定义用户提供的两种方式。
3) 是否&x
接受
这第三次检查是必要的,因为x.operator&()
可能会因为operator&
确实存在而被拒绝,但它是私有的。在这种情况下,&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>
将它用于X
多个类中的某个类,它很容易导致 ODR 违规翻译单元,有些X
是定义的,有些X
是不完整的。拥有两个独立的功能可以避免这个问题。
唯一剩下的问题是如果在定义's customaddressof<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;