gpt4 book ai didi

c++ - 有人可以向我解释以下模板代码吗?

转载 作者:行者123 更新时间:2023-11-28 01:15:17 25 4
gpt4 key购买 nike

我是模板编程的新手,我打算使用此处的解决方案来确保所使用的类型定义了运算符。但我想了解这段代码。我查阅了 cppreference 的信息,但我对它的工作原理更加困惑。

How to check whether operator== exists?

不幸的是,它对我来说非常神秘,我想会询问代码中某些内容的含义和原因。

namespace CHECK
{
struct No {};
template <typename T, typename Arg>
No operator==(const T&, const Arg&);

/* Why are there two definitions of structures? Is this needed at all? Is
* there a simpler version of this whole code snippet?
*/
template <typename T, typename Arg = T>
struct EqualExists {
/* Why does this have to be a enum? What effect does this have? */
enum {
/* What happens if == sign is not defined for T? What would the
* below comparison return when true/false? (The comparison *(T*)(0) == *(Arg*)(0))
*
* What is the need for No here? Why is it needed and how will
* comparing it with the return type of == comparison be true ever?
* How can the return type of == comparison and No structure be the same?
*/
value = !std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value
};
};
}

有人可以将此链接到原始问题吗?希望这也能帮助新接触 cpp 的人理解这一点。

最佳答案

解释

让我们一步步分解:

  • (T*)(0) : 假装有一个 T 类型的对象在地址 0;这个子表达式的类型是一个指针
  • *(T*)(0) : 假装有一个 T 类型的对象在地址 0;这个子表达式的类型是一个引用,因为前面的星号取消了对指针的引用。它看起来有点像空指针取消引用,但稍后会详细介绍。
  • *(Arg*)(0) : 假装有一个 Arg 类型的对象在地址 0;与 T 相同的模式
  • *(T*)(0) == *(Arg*)(0) : 这相当于调用 operator==<T, Arg>( *(T*)(0), *(Arg*)(0) )使用 letting the compiler figure out where the operator is defined 的额外便利.
    • 如果用户定义operator==不存在,那么CHECK namespace 运算符将被匹配。这是一个“包罗万象”的模板。
  • decltype(*(T*)(0) == *(Arg*)(0)) : decltype"don't execute the subexpression in the parentheses; just give me its type" .在这种情况下,类型是 operator== 的返回类型称呼。
    • 没有实际发生比较操作,也没有任何对内存的取消引用。
  • std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value : std::is_same valuetrue如果类型相同,或 false否则。
    • ::value是一个静态的constexpr bool
    • 两个类型参数是decltype(...)和结构CHECK::No .
    • 真实世界 operator==通常返回 bool 值。有时它可能会返回用户定义的类型。不太可能有人会写下他们的习惯 operator==返回 CHECK::No ,并且此代码依赖于该假设。
  • enum { value = !std::is_same<...>::value } : 枚举始终是编译时常量,适用于较旧的 C++ 编译器和规范(如 C++03,其中 constexpr 不存在),与 constexpr 兼容,并且不需要存储。
    • static constexpr bool value = !std::is_same<...>::value;本来是等价的。

示例代码的问题:

  • 技术上取消引用空指针是非法的; std::declval 是一个安全的选择。
  • 技术上有人可以写 CHECK::No operator==(const Foo&, const Bar&) ,这会让检查误认为运算符未定义。
  • operator==在 CHECK 命名空间中可能会隐藏全局定义的 operator== 定义,从而导致漏报。

替代实现

要解决上述问题并“简化”,一种方法是使用 SFINAE .虽然“更简单”在这里是主观的。

[编辑] 工作版本链接:http://coliru.stacked-crooked.com/a/e9cc48729d53b6c6 , 并更新了下面的代码

    template <typename T, typename Arg = T>
class EqualExists {
template <class U = T, class V = Arg, bool Exists = !!sizeof(std::declval<U>() == std::declval<V>())>
static std::true_type Func(const T&, const Arg&);

template <class U, class V>
static std::false_type Func(const U&, const V&);

public:
static constexpr bool value = decltype(Func(std::declval<T>(), std::declval<Arg>()))::value;
};

[edit] 我的原始答案有一个错误:在 Exists 计算中没有使用模板参数 U 和 V,并且在 gcc 上编译失败。 (出于某种原因在 msvc 上工作)

        template <class U, class V, bool Exists = !!sizeof(std::declval<T>() == std::declval<Arg>())>
static std::true_type Func(const T&, const Arg&);

关于c++ - 有人可以向我解释以下模板代码吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58907642/

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