Reputation: 4406
template <int C> class MyClass;
...
template <int C>
double trans(MyClass<C> &a)
{
//return some double
}
//this is supposed to be function template
template <int C>
double func(MyClass<2> &a)
{
//return some double
}
template <int C>
MyClass<C-1> func(MyClass<C> &a)
{
MyClass<C-1> ret;
return ret;
}
template <int C>
double otherFunc(MyClass<C> &a)
{
double result;
if(C == SOME_CONSTANT)
result = func(a);
else
result = trans(func(a));
}
What my problem is I want to check template argument C in parameter otherFunc
call function template func
(return double) instead of member function of class template func
(return MyClass). But somehow compiler attempts to func
that returns MyClass in
if(C == SOME_CONSTANT)
result = func(a);
this part so I got compiler error (because double = MyClass is not viable). How should I fix this problem?
Upvotes: 0
Views: 117
Reputation: 106246
Hard to elaborate in a comment, so I'll post an answer. To recap what I said in comments:
if
/else
in otherFunc
that won't be legal to compile for a specific MyClass
instantiation,otherFunc
definition to handle MyClass<2>
s.Sample code:
#include <iostream>
template <int C>
class MyClass
{ };
template <int C>
double trans(const MyClass<C> &a)
{
return C + 700;
}
template <int C>
MyClass<C-1> func(MyClass<C> &a)
{
MyClass<C-1> ret;
return ret;
}
double func(MyClass<2>& a)
{
return 200.0;
}
template <int C>
double otherFunc(MyClass<C> &a)
{
return trans(func<C>(a));
}
template <>
double otherFunc<2>(MyClass<2>& a)
{
return func(a);
}
int main()
{
MyClass<2> a;
std::cout << otherFunc(a) << '\n';
MyClass<4> b;
std::cout << otherFunc(b) << '\n';
}
Output:
200
703
Upvotes: 0
Reputation: 27595
I guess the reason is that:
if(C == SOME_CONSTANT)
result = func(a);
else
result = trans(func(a));
is checked in the runtime, while template specializations and type check is done during compilation. Those 2 functions:
template <int C>
double func(MyClass<2> &a)
{
//return some double
}
template <int C>
MyClass<C-1> func(MyClass<C> &a)
{
MyClass<C-1> ret;
return ret;
}
have almost the same signatures - the only difference is that for C==2
is used the one returning double
, otherwise used the one returning MyClass<2>
. So what you get is:
// for C==2
if(C == SOME_CONSTANT)
result = func<2>(a); // returns double - just like you wanted
else
result = trans<2>(func<2>(a)); // pass double into trans<?>(MyClass<?>), so the parameter cannot be resolved unless you specified some implicit constructor/explicit conversion operator
// for e.g. C==3
if(C == SOME_CONSTANT)
result = func<3>(a); // returns MyClass<2> while result is double
else
result = trans<2>(func<3>(a)); // pass MyClass<2> into trans<?>(MyClass<>) - like you wanted
so basically your code have invalid type for specializations in either first or second case. You can do something like this instead:
template <>
MyClass<2> func<2>(MyClass<2> &a)
{
return a;
}
template <int C>
MyClass<C-1> func(MyClass<C> &a)
{
return MyClass<C-1>;
}
to keep templates type consistent, and then:
if(C == SOME_CONSTANT)
result = trans(a);
else
result = trans(func(a));
It's just an example how to handle it. Things should be easier if you avoid messing with different return typed for different template specializations.
Upvotes: 0