了解简单?C ++部分模板专门化

如何解决了解简单?C ++部分模板专门化

|| 注意:这似乎是一个问题的转贴:C ++-重载了模板化的类方法,并且对该方法进行了部分规范化 我将C ++模板专业化遇到的问题归结为一个简单的案例。 它由一个简单的2参数模板类ѭ0组成,我想专门介绍ѭ1来表示
B=int
#include <cstdio>

//
// A 3-parameter template class.
//
template <class A,class B>
class Thing
{
public:
    Thing(A a,B b) : a_(a),b_(b) {}
    B doSomething();
private:
    A a_;
    B b_;
};

//
// The generic case works as expected.
//
template <class A,class B>
B Thing<A,B>::doSomething()
{
    return b_;
}

//
// This specialization does not work!
//
template <class A>
int Thing<A,int>::doSomething()
{
    return b_+1;
}

int main( int argc,char** argv )
{
    // Setup our thing.
    Thing<double,int> thing(1.0,2);
    // This doesn\'t compile - but works with the generic case.
    printf(\"Expecting 3,and getting %i\\n\",thing.doSomething());
    // Clean up.
    return 0;
}
不幸的是,
g++
退出并显示错误:
partial_specialization.cpp:30: error: invalid use of incomplete type ‘class Thing<A,int>’
partial_specialization.cpp:8: error: declaration of ‘class Thing<A,int>’
clang++
编译器稍微冗长一些,但存在相同的问题:
partial_specialization.cpp:30:19: error: nested name specifier \'Thing<A,int>::\' for declaration does not
      refer into a class,class template or class template partial specialization
int Thing<A,int>::doSomething()
    ~~~~~~~~~~~~~~^
partial_specialization.cpp:32:12: error: use of undeclared identifier \'b_\'
    return b_+1;
           ^
2 errors generated.
我已经阅读并理解,不允许对函数进行部分模板专门化-但在这种情况下,我认为我对
Thing
类进行了部分专门化。 有任何想法吗? 我所做的事情:一种解决方法,根据接受的答案提供的链接确定:
template< class T >
inline T foo( T const & v ) { return v; }

template<>
inline int foo( int const & v ) { return v+1; }

//
// The generic case works as expected.
//
template <class A,B>::doSomething()
{
    return foo(b_);
}
    

解决方法

标准不允许对功能模板进行部分专业化,无论是成员功能模板还是独立功能模板:
template<typename T,typename U> void f() {} //okay  - primary template
template<typename T> void f<T,int>() {}      //error - partial specialization
template<> void f<unsigned char,int>() {}    //okay  - full specialization
但是,您可以部分专门化类模板本身。您可以执行以下操作:
template <class A>
class Thing<A,int>  //partial specialization of the class template
{
    //..
    int doSomething();
};

template <class A>
int Thing<A,int>::doSomething()  { /* do whatever you want to do here */ }
请注意,当您部分专业化类模板时,成员函数的模板参数列表(在类外部的定义中)必须与类模板部分专业化的模板参数列表匹配。就是说,对于类模板的以上部分专业化,您不能定义以下内容:
template <class A>
int Thing<A,double>::doSomething(); //error
不允许这样做,因为函数定义中的模板参数列表与类模板局部特化的模板参数列表不匹配。根据标准(2003)的第14.4.5.3/1条,   类模板部分专业化的成员的模板参数列表应与类模板部分专业化的模板参数列表匹配。[...] 有关此的更多信息,请在此处阅读我的答案: C ++-重载模板化的类方法,并对该方法进行部分说明 那么解决方案是什么?您会在所有重复性工作中部分地专注于您的课堂吗? 一个简单的解决方案是工作委派,而不是部分专门化类模板。编写一个独立的功能模板,并将其专门化为:
template <class B>
B doTheActualSomething(B & b) { return b;  }

template <>
int doTheActualSomething<int>(int & b) { return b + 1; }
然后从
doSomething()
成员函数中将此函数模板调用为:
template <class A,class B>
B Thing<A,B>::doSomething() { return doTheActualSomething<B>(b_); }
由于在您的特定情况下,
doTheActualSomething
仅需要知道一个成员的值,即
b_
,上述解决方案就可以了,因为您可以将该值作为类型为模板类型实参
B
的参数传递给函数,并专门化
int
完全专业化是可能的。 但是想象一下,如果它需要访问多个成员,每个成员的类型取决于模板类型的arguments-list,那么定义一个独立的函数模板将无法解决问题,因为现在将有不止一个类型实参。函数模板,并且您不能仅对一种类型的函数进行部分专业化(因为不允许使用)。 因此,在这种情况下,您可以定义一个类模板,该类模板定义静态的非模板成员函数
doTheActualSomething
。方法如下:
template<typename A,typename B>
struct Worker
{
   B doTheActualSomething(Thing<A,B> *thing)
   {
      return thing->b_;
   }
};

//partial specialization of the class template itself,for B = int
template<typename A>
struct Worker<A,int>
{
   int doTheActualSomething(Thing<A,int> *thing)
   {
      return thing->b_ + 1;
   }
};
注意,您可以使用
thing
指针来访问该类的任何成员。当然,如果需要访问私有成员,则必须将ѭ23成为
Thing
类模板的朋友,例如:
//forward class template declaration
template<typename T,typename U> struct Worker

template <class A,class B>
class Thing
{
    template<typename T,typename U>  friend struct Worker; //make it friend
   //...
};
现在将工作委托给朋友为:
template <class A,B>::doSomething()
{
    return Worker<A,B>::doTheActualSomething(this); //delegate work
}
这里要注意两点: 在此解决方案中,“ 16”不是成员函数模板。它不是封闭的类,它是模板。因此,我们可以随时对类模板进行部分专业化,以获得部分成员函数模板专业化的理想效果。 由于我们将
this
指针作为函数的参数传递,因此我们可以访问
Thing<A,B>
类的任何成员,甚至是私有成员,因为
Worker<T,U>
也是朋友。 完整的在线演示:http://www.ideone.com/uEQ4S 现在仍有改进的机会。现在,
Worker
类模板的所有实例都是
Thing
类模板的所有实例的朋友。因此,我们可以将这种多对多友谊限制为:
template <class A,class B>
class Thing
{
    friend struct Worker<A,B>; //make it friend
   //...
};
现在,只有
Worker
类模板的一个实例是
Thing
类模板的一个实例的朋友。那是一对一的友谊。也就是说,
Worker<A,B>
Thing<A,B>
的朋友。
Worker<A,B>
不是
Thing<A,C>
的朋友。 此更改要求我们以略有不同的顺序编写代码。请参阅完整的演示,其中包括类和函数定义的所有排序以及所有: http://www.ideone.com/6a1Ih     ,这是一个非常常见的问题,并且有一个非常简单的解决方案。我将在一个人工示例中展示它,因为它比使用您的代码更清晰,并且您必须了解它以使其适应您的代码
template<typename A,typename B>
struct TwoTypes { };

template<typename A,typename B>
struct X {
  /* forwards ... */
  void f() { fImpl(TwoTypes<A,B>()); }

  /* special overload for <A,int> */
  template<typename A1>
  void fImpl(TwoTypes<A1,int>) {
    /* ... */
  }

  /* generic */
  template<typename A1,typename B1>
  void fImpl(TwoTypes<A1,B1>) {
    /* ... */
  }
};
明确地专门化函数是永远不会(几乎永远不会?)正确的方法。在我作为程序员的工作中,我从未明确地专门设计过函数模板。重载和部分排序比较好。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-