C++ 有人能给我解释一下下面的模板代码吗?

C++ 有人能给我解释一下下面的模板代码吗?,c++,templates,C++,Templates,我是模板编程新手,我打算使用这里的解决方案来确保使用的类型定义了运算符。但是我想理解这个代码。我查阅了CPPPreference的信息,但我更不清楚它是如何工作的 不幸的是,它对我来说是相当神秘的,我想它会询问代码中某些内容的含义和原因 namespace CHECK { struct No {}; template <typename T, typename Arg> No operator==(const T&, const Arg&);

我是模板编程新手,我打算使用这里的解决方案来确保使用的类型定义了运算符。但是我想理解这个代码。我查阅了CPPPreference的信息,但我更不清楚它是如何工作的

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

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
        };
    };
}
名称空间检查
{
结构号{};
模板
无运算符==(常数T&,常数Arg&);
/*为什么有两种结构的定义?需要吗?需要吗
*整个代码段有没有更简单的版本?
*/
模板
结构均衡论者{
/*为什么必须是枚举?这有什么影响*/
枚举{
/*如果没有为T定义==符号,会发生什么情况
*当为真/假时,下面的比较返回值?(比较*(T*)(0)=*(Arg*)(0))
*
*什么是不需要这里?为什么需要它和如何将
*将其与返回类型==比较是否为真?
*==比较和无结构的返回类型如何相同?
*/
value=!std::值是否相同::值
};
};
}
有人能把这和原来的问题联系起来吗?希望这也能帮助cpp新手理解这一点。

解释 让我们一步一步地把它分解:

  • (T*)(0)
    :假设地址0处有一个
    T
    类型的对象;此子表达式的类型是指针
  • *(T*)(0)
    :假设地址0处有一个
    T
    类型的对象;此子表达式的类型是引用,因为前面的星号取消了对指针的引用。它看起来有点像一个空指针解引用,但稍后会详细介绍
  • *(Arg*)(0)
    :假设地址0处有一个
    Arg
    类型的对象;与T相同的模式
  • *(T*)(0)==*(Arg*)(0)
    :这相当于调用
    操作符==(*(T*)(0),*(Arg*)(0))
    ,具有额外的方便性。
    • 如果用户定义的
      运算符==
      不存在,则将匹配
      检查
      命名空间运算符。这是一个“全面”的模板
  • decltype(*(T*)(0)==*(Arg*)(0))
    decltype
    说。在这种情况下,类型是
    操作符==
    调用的返回类型。
    • 实际上不会发生比较操作,也不会解除对内存的限制
  • std::is_same::value
    :'s
    value
    如果类型相同,则为
    true
    ,否则为
    false
    • ::value
      是一个静态constexpr bool
    • 这两个类型参数是
      decltype(…)
      和struct
      CHECK::No
    • 真实世界的
      操作符==
      通常返回bool。有时它可能返回用户定义的类型。不太可能有人会编写自定义的
      操作符==
      来返回
      检查::No
      ,而此代码依赖于该假设
  • <>代码>枚举值> .STD::ISHYNE::值} /COD>:枚举总是编译时常数,适用于旧的C++编译器和规范(如C++ 03,其中代码> COSTEXPRO< /CODE >不存在),与<代码> CONTXPRP</代码>兼容,不需要存储。
    • static constexpr bool value=!std::is_same::value将是等效的
示例代码的问题:
  • 从技术上讲,取消对空指针的引用是非法的;这是一个安全的选择
  • 从技术上讲,有人可以编写
    CHECK::No operator==(const Foo&,const Bar&)
    ,这会使CHECK误认为运算符未定义
  • 检查命名空间中的
    运算符==
    可能会对全局定义的运算符==定义产生阴影,从而导致误判
替代实施 要解决上述问题并“简化”,一种方法是使用。虽然“简单”在这里是主观的

[编辑]链接到工作版本:,并更新下面的代码

    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;
    };
模板
阶级平等主义者{
模板
静态std::true_type Func(常量T&,常量Arg&);
模板
静态std::false_类型Func(常量U&,常量V&);
公众:
静态constexpr bool value=decltype(Func(std::declval(),std::declval())::value;
};
[编辑]我的原始答案有一个bug:在Exists计算中没有使用模板args U和V,在gcc上编译失败。(出于某种原因在msvc工作)

模板
静态std::true_type Func(常量T&,常量Arg&);
说明 让我们一步一步地把它分解:

  • (T*)(0)
    :假设地址0处有一个
    T
    类型的对象;此子表达式的类型是指针
  • *(T*)(0)
    :假设地址0处有一个
    T
    类型的对象;此子表达式的类型是引用,因为前面的星号取消了对指针的引用。它看起来有点像一个空指针解引用,但稍后会详细介绍
  • *(Arg*)(0)
    :假设地址0处有一个
    Arg
    类型的对象;与T相同的模式
  • *(T*)(0)==*(Arg*)(0)
    :这相当于调用
    操作符==(*(T*)(0),*(Arg*)(0))
    ,具有额外的方便性。
    • 如果用户定义的
      运算符==
      不存在,则将匹配
      检查
      命名空间运算符。这是一个“全面”的模板
  • decltype(*(T*)(0)==*(Arg*)(0))
    decltype
    说。在这种情况下,类型是
    操作符==
    调用的返回类型。
    • 实际上没有发生比较操作,n
              template <class U, class V, bool Exists = !!sizeof(std::declval<T>() == std::declval<Arg>())>
              static std::true_type Func(const T&, const Arg&);