Let say i have two classes MyClass_one
, MyClass_two
And i have function that accept only them as first parameter
template<typename T,typename ...Ts>
void doSomething(T one, Ts...two){}
Now to make it simple, if parameter one
is MyClass_one
it should print "im one" if its MyClass_two
it should print "im two".
How to actually achieve this? The only solution i have came up with is really ugly and does not containt compile error throwing:
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;}
}
However how to implement the compiler error check without overloading (multiple definition of doSomething()
function) e.g the function will not compile if something else than MyClass_one
or MyClass_two
is passed.
thanks for help.
答案 0 :(得分:5)
If you can use C++17, you can use 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;}
}
Of course, isOne<T>::value
and isTwo<T>::value
need to be static constexpr
variables.
If you want to check the types of the first function argument, the same approach holds, only there is no need for something like isOne
and isTwo
, you can use std::is_same_v
to see if the first argument is 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>
results in atrue
value if the types A
and B
are the same. This answers your question "if parameter one is MyClass_one it should print "im one" if its MyClass_two it should print "im two".", and fails at compile time if the first argument is any type different than etither myClassOne
or myClassTwo
.
Edit: added a static_assert
that makes sure the compilation fails if the first argument is anything else except MyClassOne
or MyClassTwo
, as suggested by Justin Time in the comment.
答案 1 :(得分:3)
没有超载
但是这里的重载使代码变得简单:
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;
}
答案 2 :(得分:2)
我建议将您的功能分为两部分。保留迭代部分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
非专业类型进行编译。