c++ - 运算符重载嵌套在类中的枚举

标签 c++ templates operator-overloading c++14 friend-function

问题

给定以下代码:

template <typename T>
struct dummy {
  enum enumenum { a = 1, b = 2, c = 4 };
};

int main() { 
    // I want this line to expands as : 
    // dummy<double>::enumenum a = operator~(dummy<double>::a);
    auto a = ~dummy<double>::a;
}

如何在 enumenum 上重载运算符? 我正在使用标准 C++14。

我尝试过的

一个简单的实现:

template <typename T>
typename dummy<T>::enumenum 
operator~(typename dummy<T>::enumenum a) {
  return static_cast<typename dummy<T>::enumenum>(operator~(a));
}

不幸的是,有问题的行扩展为:

int a = ~static_cast<int>(dummy<double>::a);

这意味着未使用运算符(这是默认行为)。 是因为 ADL 无法在结构命名空间中找到正确的 operator~()(这甚至是一回事吗?)?

然后我尝试了:(注意 friend )

template <typename T>
struct dummy {
  enum enumenum { a, b, c };
  
  friend enumenum operator~(enumenum a) { 
    return static_cast<enumenum>(~a);
  }
};

这实际上工作并扩展为:

template <>
struct dummy<double> {
  enum enumenum {
    a = static_cast<unsigned int>(1),
    b = static_cast<unsigned int>(2),
    c = static_cast<unsigned int>(4)
  };

  friend inline dummy<double>::enumenum operator~(dummy<double>::enumenum a) {
    return static_cast<dummy<double>::enumenum>(operator~(a));
  }
};

int main()
{
  dummy<double>::enumenum a = operator~(dummy<double>::a);
}

这是我想要的行为。除非,如果我不想在类主体中定义运算符怎么办。

所以我尝试了:

template <typename T>
struct dummy {
  enum enumenum { a = 1, b = 2, c = 4 };
  
  // if inline : inline function 'operator~' is not defined [-Wundefined-inline]
  // and adding inline to the template below does not help
  friend enumenum operator~(enumenum a);
};

template <typename T>
typename dummy<T>::enumenum 
operator~(typename dummy<T>::enumenum a) {
  return static_cast<typename dummy<T>::enumenum>(~a);
}

int main() { 
    auto a = ~dummy<double>::a; 
}

上面的代码扩展为:

template<>
struct dummy<double>
{
  enum enumenum
  {
    a = static_cast<unsigned int>(1), 
    b = static_cast<unsigned int>(2), 
    c = static_cast<unsigned int>(4)
  };
  
  friend dummy<double>::enumenum operator~(dummy<double>::enumenum a);
};

int main()
{
  dummy<double>::enumenum a = operator~(dummy<double>::a);
}

这会编译,但不会链接! 编辑:我相信它没有链接,因为模板没有实例化,因此在链接时失败(类似于上面的天真实现)。

结论

尽管我以某种方式找到了实现我想要的方法,但如果我不想在类定义中定义运算符怎么办。

提前致谢。

最佳答案

This compiles, but does not link!

编译但不链接,因为你声明了一个非模板运算符(它在模板结构中但不是模板函数)

friend enumenum operator~(enumenum a);

然后你定义一个模板

template <typename T>
typename dummy<T>::enumenum 
operator~(typename dummy<T>::enumenum a) {
  return static_cast<typename dummy<T>::enumenum>(~a);
}

并且模板定义不能匹配非模板声明。

您可以尝试将函数声明为模板一

template <typename T>
struct dummy
 {
   enum enumenum { a = 1, b = 2, c = 4 };

   template <typename U>
   friend typename dummy<U>::enumenum
      operator~ (typename dummy<U>::enumenum const & a);
 };

template <typename T>
typename dummy<T>::enumenum 
      operator~ (typename dummy<T>::enumenum const & a)
 { return static_cast<typename dummy<T>::enumenum>(~a); }

int main ()
 { 
   auto a = ~dummy<double>::a; 
 }

但是,不幸的是,这个编译但是,调用了~运算符如下

 ~dummy<double>::a;

没有调用模板函数,因为模板参数 T正如 Benny K 在评论中所指出的那样,无法推断是因为它处于非推断上下文中(在最后一个 :: 之前)。

因此,取而代之的是模板 operator~() , dummy<double>::a转换为 int~ int 的运算符已应用(结果类型为 int )。

您可以显式调用一个函数来验证这一点 operator~()

 auto a = operator~(dummy<double>::a); 

你应该得到一个“没有匹配的函数来调用'operator~'”错误(注释“注意:候选模板被忽略:无法推断模板参数'T'”)或类似的东西。

要使这个解决方案有效,您必须明确类的类型,以避免模板推导

 auto a = operator~<double>(dummy<double>::a); 

现在,您可以验证 adummy<double>::enumenum

 static_assert( std::is_same<decltype(a), dummy<double>::enumenum>::value, "!" );

但是,显然,这不是一个令人满意的解决方案(而且非常危险,如果您忘记避免简单地使用 ~ )。

否则你可以将运算符定义为非模板

template <typename T>
struct dummy
 {
   enum enumenum { a = 1, b = 2, c = 4 };

   friend enumenum operator~ (enumenum const & a);
 };

dummy<double>::enumenum 
      operator~(dummy<double>::enumenum const & a)
 { return static_cast<dummy<double>::enumenum>(~a); }

int main ()
 { 
   auto a = ~dummy<double>::a; 
 }

但你必须为每个 dummy<T> 定义不同的运算符类型。

恕我直言,最简单、安全和优雅的解决方案是您的工作解决方案:在结构中声明/定义运算符。

关于c++ - 运算符重载嵌套在类中的枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63052236/

相关文章:

c++ - 有没有办法将函数从 objective-c++ 传递到标准 c++?

templates - Kendo Grid DetailTemplate,访问SubGrid值的条件表达式

使用模板链表和指针传递的 C++ 未解析外部符号

javascript - Django 动态字段 - 无法从模板中添加的多个行获取数据

c++ - 如何在两个不同类之间重载 '==' 运算符?

c++ - cout一个类的函数

c++ - 在 cmake 中制作宏脚本并在源文件中调用该宏

C++控制台游戏,故障重新切换语句以在二维数组中移动字符

c++ - 取消引用适用于 ptr->operator*() 但不适用于 *ptr

c++ - 为什么在全局变量的析构函数中调用 thread.join 会失败