根据模板类型在类中提供/启用方法

2024-01-06

我正在编写代码并决定添加对标量类型的支持,以便能够在std::complex<double>和朴素的double。我已经写好了所有的数字运算,并用template <typename Scalar>方法。

我的“问题”是,对于复杂的情况,我需要提供一些在实际情况下没有意义且无法编码的附加方法。

我以前的方法是创建一个基类模板,它实现了所有常见的内容。然后我有一个从这个基类派生的具体类,作为Scalar模板参数std::complex<double>。然后我有一种模板代理/虚拟类,其行为就像在double版本和std::complex<double>。它看起来或多或少像下面这样。

//base stuff
template<typename Scalar>
class NumberCruncherBase{
 Scalar stuff1();
 Scalar stuff2();
 Scalar stuff3();
}

//inherit base stuff and extend it
class NumberCruncherComplex : public NumberCruncherBase< std::complex<double> >{
 std::complex<double> extra_stuff1();
}

//switch proxy
template<typename Scalar>
class NumberCruncher : public NumberCruncherBase<Scalar> {}

//specialization for complex to explicitly derive from the extension
//in case of complex
template<>
class NumberCruncher< std::complex<double> > : public NumberCruncherBase< std::complex<double> > {}

令人惊讶的是,这种方法效果还不错。你可以从NumberCruncher或直接来自具体的专业类型。还可以提供NumberCRuncherReal为了一致性,但这有点毫无意义。

然而,这样的代码编写起来有点麻烦,而且重复的代码感觉很臃肿。我需要为基类中的每种类型提供包装器。

我最近遇到了boost's enable_if这似乎可以满足我的需要。但我无法让它发挥作用。我累了:

 const Matrix op_My( typename enable_if<boost::is_complex<Scalar> >::type* dummy = 0 ) { return g*H_sum_S[2]; };

这是类声明中的一行,g++ says:

 error:   expected a constant of type ‘bool’, got ‘boost::is_complex<Scalar>’

我的问题是,这是实现我所追求的目标的好技术吗?以及我应该怎么写。我试着跟随http://www.boost.org/doc/libs/1_54_0/libs/utility/enable_if.html http://www.boost.org/doc/libs/1_54_0/libs/utility/enable_if.html。我使用海湾合作委员会4.8.1。


您收到的具体错误是因为enable_if 采用 bool 作为第一个参数,但您向它传递了一个类型。

boost::is_complex<Scalar> // <- this is a type 

要获取布尔值(true/false),您需要编写:

boost::is_complex<Scalar>::value // <- this is a bool value telling whether Scalar is complex

is_complex 结构继承自 true_type 或 false_type (取决于 Scalar 的类型),如果您想更详细地了解它是如何工作的,请查找它们;)

不过,您的代码还存在其他问题。 enable_if 需要依赖于调用函数时首先知道的模板参数,而不是类模板参数。你可以这样做:

template<typename Scalar> 
class matrix
{
//...
   public:
   // print function that will be called for a matrix of complex numbers
   template<typename T=Scalar
          , typename std::enable_if<boost::is_complex<T>::value,int>::type = 0
          >
   void print() const;

   // print function that will be called for a matrix of non-complex numbers
   template<typename T=Scalar
          , typename std::enable_if<!boost::is_complex<T>::value,int>::type = 0
          >
   void print() const;
   //...
};

这将产生一个“开关”,根据类模板参数选择适当的类方法。按照惯例,我选择将enable_if 放在模板参数中,而不是放在函数签名中。我发现这是一个更通用的解决方案,并且更具可读性。

我不知道这是否是提供此功能的“最佳”方式(我无法想到任何主要缺点),但它会解决问题。希望能帮助到你 :)

编辑 2013 年 8 月 11 日:

我使用特定类型的enable_if结构,因为它允许我在两个函数之间进行enable_if切换,否则这两个函数将具有完全相同的签名。使用enable_if的“通常”方法之一是使用enable_if的结果作为模板参数的默认值,如下所示:

template<typename Scalar> 
class matrix
{
//...
   public:
   // print function that will be called for a matrix of complex numbers
   template<typename T=Scalar
          , class = typename std::enable_if<boost::is_complex<T>::value>::type // enable_if is used to give default type for the class template
          >
   void print() const; 

   // print function that will be called for a matrix of non-complex numbers
   template<typename T=Scalar
          , class = typename std::enable_if<!boost::is_complex<T>::value>::type // same as above
          >
   void print() const; //<- this has same function signature as the above print()
                       //   we get a compiler error
   //...
};

编译器无法区分这两个打印函数,因为它们都以相同的方式模板化,并且具有相同的签名,因为它们都被视为

template<typename T, typename U>
void print() const;

在我的示例中,编译器不知道函数是如何模板化的,因为这是由enable_if的结果决定的

template<typename T, ?>
void print() const;

因此,当函数被调用并且enable_if被评估时,可以首先看到函数签名。按照惯例,我选择了 int,但你也可以使用 void*:

typename std::enable_if<!boost::is_complex<T>::value,void*>::type = nullptr

用 void* 代替 int,但不仅仅是 void,因为我们不能有 void 非类型模板参数。

为了完成您想做的事情,您需要在派生类中提供一个非模板化函数来覆盖基类中的抽象函数。为此你可以使用间接并做类似的事情:

class matrix_base
{
   public:
      virtual void print() const = 0;
};

template<typename Scalar>
class matrix: matrix_base
{
   //...
   private:
      // print function that will be called for a matrix of complex numbers
      template<typename T=Scalar
             , typename std::enable_if<boost::is_complex<T>::value,int>::type = 0
             >
      void print_impl() const;

      // print function that will be called for a matrix of non-complex numbers
      template<typename T=Scalar
             , typename std::enable_if<!boost::is_complex<T>::value,int>::type = 0
             >
      void print_impl() const;

   public:
      // print function that will override abstract print in base class
      void print() const { print_impl(); } // <- redirect to one of the print_impl() functions

      //...
};

这种方法的缺点是您需要为每种可能的矩阵类型提供 print_impl() 实现,即您不能只为复数提供 print_impl() 实现,还需要为非复数提供一个 print_impl() 实现。

希望这能让一些事情变得更清楚:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

根据模板类型在类中提供/启用方法 的相关文章

  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • MVC3中设置下拉列表中的所选项目

    我必须为视图中的下拉列表设置所选项目 但它不起作用 View div class editor label Html LabelFor model gt model Gender div div class editor field Htm
  • extern 声明和函数定义都在同一文件中

    我只是浏览了一下gcc源文件 在gcc c 我发现了类似的东西 extern int main int char int main int argc char argv 现在我的疑问是extern是告诉编译器特定的函数不在这个文件中 但可以
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • Eigen 和 OpenMP:由于错误共享和线程开销而没有并行化

    系统规格 Intel Xeon E7 v3 处理器 4 插槽 16 核 插槽 2 线程 核心 Eigen 系列和 C 的使用 以下是代码片段的串行实现 Eigen VectorXd get Row const int j const int
  • 什么是空终止字符串?

    它与什么不同标准 字符串 http www cplusplus com reference string string 字符串 实际上只是一个数组chars 空终止字符串是指其中包含空字符的字符串 0 标记字符串的结尾 不一定是数组的结尾
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 如何将AVFrame转换为glTexImage2D使用的纹理?

    如您所知 AVFrame 有 2 个属性 pFrame gt data pFrame gt linesize 当我从视频 sdcard test mp4 android平台 读取帧后 并将其转换为RGB AVFrame副 img conve
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • 从 C# 使用 Odbc 调用 Oracle 包函数

    我在 Oracle 包中定义了一个函数 CREATE OR REPLACE PACKAGE BODY TESTUSER TESTPKG as FUNCTION testfunc n IN NUMBER RETURN NUMBER as be
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • Oauth2中如何同时撤销RefreshToken和使AccessToken失效

    我正在使用 Owin Oauth2 授权和资源服务器相同 开发单页面应用程序 AngularJS Net MVC Json Rest API 的身份验证流程 我选择了 Bearer Token 路由而不是传统的 cookie session
  • 模板类的模板构造函数的 C++ 显式模板特化

    我有一个像这样的课程 template
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • Visual Studio 2015:v120 与 v140?

    仅供参考 Win10 x64 我今天开始尝试 Visual Studio 2015 在弄清楚如何运行 C C 部分后 我尝试加载一个大型个人项目 该项目使用非官方的glsdk http glsdk sourceforge net docs
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • 我可以使用 lambda 函数或 std::function 对象来代替函数指针吗?

    我有一个需要使用的库 它定义了以下内容 typedef void CallbackFunction const int i 并且有一个注册回调的函数 如下所示 void registerCallback CallbackFunction p

随机推荐