Valen
Valen

Reputation: 1763

template-type-related compile time error occur where theoretically not

I have a template function template<class T> T exc(T()) where T can sometime be void.

This function is used to execute a function and return the value (if it's not void).

This is the simplified content of exc (of course I have other content =p)

template<class T> T exc(T (*func)()){
    if(strcmp(typeid(T).name(), "void")){
        T obj = (*func)();
        // there are something to do with obj
        return obj;
    } else{
        (*func)();
    }
}

// in main:
exc<void>([]() -> void{std::cout << "I'm too lazy to type another function"
        << " so I use lambda" << std::endl;});

As you may know, strcmp return 0 when typeid(T).name() equals to "void".

That is, there are no problem with runtime theoretically. However, this is the error

error C2182 : illegal use of type 'void'

I use MSVC cl command line compiler, and I think the problem may be caused by the compiler which substitute each template type from where function is invoked for T, so at T obj, the error occur.

I want to ask that is there any alternate solution for this? Is there any other way to declare obj so that the compiler treat it as 'correct'? Or should I override exc with void exc(void (*func)())?

Upvotes: 2

Views: 72

Answers (3)

Marco A.
Marco A.

Reputation: 43662

Overloading is the answer if your "actual code" does something more involved with the templated type

template<class T> T exc(T (*func)()){
        T obj = (*func)();
        // there's something to do with obj
        return obj;
}

void exc(void (*func)()){
        // something to do with void?
        (*func)();
}

(anyway you will not be able to explicitly state the template parameter in the void case, a specialization could do it but pay attention to some overloading vs specialization resolutions).

Finally you could as well return a void call

void fun() {}

template <class T>
T exc(T (*func)()) {
    return func();
}

exc<void>(fun);

One thing to keep in mind is that when compiling templated code, all the in-scope branches should be valid at any time. An if branch is NOT going to be "dead-code eliminated" magically if the templated type doesn't match - it will yield an error.

Upvotes: 2

Jarod42
Jarod42

Reputation: 217293

You have error because the two branches has to be valid and

if(strcmp(typeid(T).name(), "void")){
    T obj = (*func)();
    // there are something to do with obj
    return obj;
}

is not valid for T == void (even if the branch would not be taken)

You may use overload to solve your problem:

template<class T> T exc(T (*func)()){
    T obj = (*func)();
    // there are something to do with obj
    return obj;
}

void exc(void (*func)()){
    (*func)();
}

Upvotes: 1

Quentin
Quentin

Reputation: 63124

Just do :

template <class T>
T exc(T (*func)()) {
    return func();
}

You can return an expression of void type from a void function.

Edit: if you need to apply a special treatment to obj, don't specialize your function template. Overload it :

void exc(void (*func)()) {
    func();
}

Upvotes: 2

Related Questions