c++ - 允许模板参数仅是某些类型并根据它决定操作
问题描述
假设我有两节课MyClass_one
,MyClass_two
我有只接受它们作为第一个参数的函数
template<typename T,typename ...Ts>
void doSomething(T one, Ts...two){}
现在为了简单起见,如果参数one
是MyClass_one
它应该打印“im one”,如果MyClass_two
它应该打印“im two”。
如何真正实现这一目标?我想出的唯一解决方案真的很丑,并且不包含编译错误抛出:
template<typename T> isOne{ static const bool value = false}
template<> isOne<MyClass_one>{ static const bool value = true}
template<typename T> isTwo{ static const bool value = false}
template<> isTwo<MyClass_two>{ static const bool value = true}
template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
if( isOne<T>::value ) { cout << "im one" << endl;}
else if ( isTwo<T>::value){ cout <<"im two" << endl;}
}
然而,如何在不重载(函数的多个定义)的情况下实现编译器错误检查,例如,如果传递了ordoSomething()
之外的其他内容,则该函数将无法编译。MyClass_one
MyClass_two
感谢帮助。
解决方案
如果你可以使用 C++17,你可以使用if constexpr
:
template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
if constexpr ( isOne<T>::value ) { cout << "im one" << endl;}
else if constexpr ( isTwo<T>::value){ cout <<"im two" << endl;}
}
当然,isOne<T>::value
并且isTwo<T>::value
需要是static constexpr
变量。
如果你想检查第一个函数参数的类型,同样的方法也成立,只是不需要像isOne
and之类的东西isTwo
,你可以用它std::is_same_v
来查看第一个参数是MyClassOne
or MyClassTwo
:
#include <iostream>
#include <type_traits>
#include <vector>
class MyClassOne {};
class MyClassTwo {};
template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
if constexpr ( std::is_same_v<T, MyClassOne> )
std::cout << "im one" << std::endl;
else if constexpr ( std::is_same_v<T, MyClassTwo> )
std::cout <<"im two" << std::endl;
else
static_assert(false, "Only MyClassOne and MyClassTwo are permitted first arguments.");
}
int
main(int argc, char **argv) {
MyClassOne one;
MyClassTwo two;
doSomething(one, 1.5, two);
doSomething(two, 'c', one);
std::vector<MyClassOne> onesVector;
doSomething(onesVector, 1.0);
}
std::is_same_v<A,B>
true
如果类型A
和B
相同,则产生一个值。这回答了您的问题“如果参数一个是 MyClass_one,它应该打印“im one”,如果它的 MyClass_two 它应该打印“im two”。”,并且如果第一个参数是任何不同于 etithermyClassOne
或的类型,则在编译时失败myClassTwo
。
编辑:添加了一个,如果第一个参数是除orstatic_assert
之外的任何其他内容,则确保编译失败,正如 Justin Time 在评论中所建议的那样。MyClassOne
MyClassTwo
推荐阅读
- sql - 选择计数(不同)返回不正确的计数
- java - 指定的编译器合规性为 1.6,但使用了 JRE 1.8
- scala - 找不到数据源:ignite
- python - 修改字典列表的 Pythonic 方法
- python - 从列表创建组合并删除如果子字符串到分隔符字符在列表项的多个子元素中
- unetstack - 使用 unetstack 中的 trace.nam 跟踪从源到目标的数据包以进行多跳通信
- google-apps-script - 如何修复错误“对 bigquery.jobs.query 的 API 调用失败并出现错误:在 .... 遇到““FROM”“来自“。期待:“)”'
- php - 如何将项目插入现有数组
- vba - 循环遍历子文件夹中的 Excel 文件,并将数据复制并粘贴到一张工作表中
- c++ - 有条件地将 std::string 分配为引用