Since the function template in the following code is a member of a class template, it can't be specialized without specializing the enclosing class.
But if the compiler's full optimi开发者_运维知识库zations are on (assume Visual Studio 2010), will the if-else-statement in the following code get optimized out? And if it does, wouldn't it mean that for all practical purposes this IS a function template specialization without any performance cost?
template<typename T>
struct Holder
{
T data;
template<int Number>
void saveReciprocalOf();
};
template<typename T>
template<int Number>
void Holder<T>::saveReciprocalOf()
{
//Will this if-else-statement get completely optimized out
if(Number == 0) data = (T)0;
else data = (T)1 / Number;
}
//-----------------------------------
void main()
{
Holder<float> holder;
holder.saveReciprocalOf<2>();
cout << holder.data << endl;
}
Chances are it will be optimized. But if you want to be sure you can use a compile-time if
by using templates, e.g. Boost’s MPL if_
implementation.
Or you can use SFINAE (Boost.enable_if
).
Usually the way to solve this kind of problem is through overloading
template<typename T>
struct Outer {
template<int I>
void inner() {
inner(int_<I>());
}
private:
template<int I>
struct int_ { };
void inner(int_<0>) {
// for I == 0
}
template<int I>
void inner(int_<I>) {
// for others...
}
};
This mimics explicit specializations quite well, and even works in cases where type check for the other paths would go mad (unlike the if
solution)
// ...
template<int I>
void inner(int_<I>) {
int tmp[I];
}
// ...
That works because this path is only taken if I != 0
. Now in your case, i first of all wonder why you don't just pass a normal function argument. You don't seem to need the compile time nature of I
.
// works just fine too in your example
template<typename T>
void Holder<T>::saveReciprocalOf(int Number)
{
// Will this if-else-statement get completely optimized out
if(Number == 0) data = (T)0;
else data = (T)1 / Number;
}
This also has good chances of being optimized if the compiler inlines the function call. Using the template non-type parameter where it's not strictly necessary only limits the abilities of that function not to work with runtime values.
Thanks. Since I want to be certain the conditional is optimized out (because it needs to called very often deep inside loops and I use a switch-case outside the loops to pick the correct path), I'll probably end up using enable_if_c something like in the following code:
using boost::enable_if_c;
template<typename T>
struct Dummy
{
template<int N>
typename enable_if_c<N==2,bool>::type isPrimary() {return true;}
template<int N>
typename enable_if_c<N==3,bool>::type isPrimary() {return true;}
template<int N>
typename enable_if_c<N==5,bool>::type isPrimary() {return true;}
template<int N>
typename enable_if_c<N!=2&&N!=3&&N!=5,bool>::type isPrimary() {return false;}
};
To me this seems a bit less cluttered than the suggestion by Johannes. Although the last (default) case can get quite ugly.
精彩评论