仅允许模板参数为某些类型并基于它决定操作

Allowing template parameter to be only certain types and deciding action based on it

本文关键字:于它 决定 操作 类型 许模板 参数      更新时间:2023-10-16

假设我有两个类MyClass_oneMyClass_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;}
}

但是,如何在不重载的情况下实现编译器错误检查(doSomething()函数的多个定义),例如,如果传递了MyClass_oneMyClass_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>::valueisTwo<T>::value需要static constexpr变量。

如果要检查第一个函数参数的类型,同样的方法成立,只是不需要像isOneisTwo这样的东西,你可以用std::is_same_v来查看第一个参数是MyClassOne还是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); 
}  

如果AB的类型相同,则std::is_same_v<A,B>生成true值。这回答了您的问题"如果参数 1 MyClass_one则它应该打印"im one",如果它MyClass_two它应该打印"im two".",并且如果第一个参数是与 etither myClassOnemyClassTwo 不同的任何类型的参数,则在编译时失败。

编辑:添加了一个static_assert,如果第一个参数是除MyClassOneMyClassTwo以外的任何其他参数,请确保编译失败,正如贾斯汀时间在评论中建议的那样。

无过载

但是这里的重载使代码变得简单:

template<typename ... Ts>
void doSomething(MyClass_one, Ts...two){
    cout << "im one" << endl;
}
template<typename ... Ts>
void doSomething(MyClass_two, Ts...two){
    cout <<"im two" << endl;
}

我建议将函数分成两部分。保持迭代部分doSomething,并分离出您想要完成的实际事情。

template<typename T> void theThing(T one);
template<>
void theThing<MyClass_one>(MyClass_one one) {
    cout << "im one" << endl;
}
template<>
void theThing<MyClass_two>(MyClass_two one) {
    cout << "im two" << endl;
}
template<typename T, typename ... Ts>
void doSomething(T one, Ts...two) {
    theThing(one);
}

这样,您就可以为要使用的每个类提供专门的东西。奖励,它不会针对theThing不专门针对的类型进行编译。

相关文章: