tags:

views:

140

answers:

5

Is it possible to actually use the type passed as a template for control flow? I'd like to write a function that uses templates, which in turn calls another function based on the type passed:

template <class T> void test_function (T var)
{
    //Do stuff
    if (T == char) {
        bar (var);
    } else {
        foo (var);
    }
    //Do even more stuff
}

If not, I'll have to fallback to enums...

Edit: All the answers up to now advise me to use template specialization. I wasn't very specific, but this is the same as not using templates at all because for every different type there's a single, different function call.

+1  A: 

You can use template specialization for this. It means that you can define different implementations for generic void test_function(T) and specific void test_function(char)

shura
Yes, that's one of possibilities, but I'd prefer to use templates because it's only a single function call that differentiates between versions, and there is a different function call for each type I'll use with the function.
MeDiCS
@MeDiCS: But in C++ a compile-time `if` is done by specialization. Either you specialize for each type, or you overload. There is no other way to do this.
sbi
@sbi: Got it, thanks. I can now understand a bit more why some people seem to hate C++ ¬¬.
MeDiCS
There's nothing to hate. Consider your design flawed, for instance. I'm not saying it is, but hating a language because of something as trivial and common as specialization is foolish, when there are a multitude of other things that could be the problem.
GMan
@GMan: Probably. I'm used to dynamic languages such as Python, and also C. I said that because I expected the feature to solve a whole class of type problems, both dynamic and static. The problem was actually in my initial assumptiom. (Also, the syntax is terrible :P)
MeDiCS
+4  A: 

It is possible to do this, but it is almost never a good idea to do it. A better idea is just to factor out the common bits and provide an overload for the function for those specific types, e.g.

template <class T> void test_function_prologue (T var)
{
    //Do stuff
}

template <class T> void test_function_epilogue (T var)
{
    //Do even more stuff
}

template <class T> void test_function (T var)
{
    test_function_prologue(var);
    foo (var);
    test_function_epilogue(var);
}

void test_function (char var)
{
    test_function_prologue(var);
    bar (var);
    test_function_epilogue(var);
}
Tyler McHenry
+1: I find this form of non-template overloading much cleaner.
quamrana
Here's a detailed argument for overloading instead of specialization when it comes to free functions: http://www.gotw.ca/publications/mill17.htm
Tyler McHenry
+6  A: 

You usually use specialization for that:

template<class T> void forward(T t) {
    // ...
}

template<> void forward<char>(char c) {
    // ...
}

template<class T> void test(T t) {
    forward<T>(t);
}

This gives you effectively "compile-time branching".

Georg Fritzsche
The `<char>` was misplaced (it was actually overloading the template with another template that has an unnamed non-type template parameter of type `char` :)). Fixed, hope you don't mind :)
Johannes Schaub - litb
Indeed, thanks :)
Georg Fritzsche
Another approach for where you want to do nothing for most types: `void forward(...) {}` will match all types and do nothing, and then you just need overloads of `forward(char)` etc. for the types you want to actually act on.
Daniel Earwicker
+2  A: 

As long as foo() accepts an argument of type char and bar() accepts any T, it would be possible. Otherwise not. Both branches have to be compilable for any T you instantiate the template with, even if one branch is never taken. If both branches are not compilable for any T, you have no option than to use compile-time branching (which is preferable in any case).

Otherwise you might use Runtime Type Identification:

if (typeid(T) == typeid(char))

or a compile-time check:

if (boost::is_same<T, char>::value)

where is_same might be implemented as

template <class T, class U>
struct is_same { static const bool value = false; };

template <class T>
struct is_same<T, T> { static const bool value = true; };
UncleBens
+1  A: 

Even with your edited response, I'll still suggest template specialization. You just make a proxy function that calls the function you want:

template <class T> void call_other_function(T var)
{
   foo(var);
}

template <> void call_other_function<char>(char var)
{
   bar(var);
}

template <class T> void test_function (T var)
{
    //Do stuff
    call_other_function(var);
    //Do even more stuff
}
miked