与模板类型相关的编译时错误发生在理论上不发生的地方

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

本文关键字:理论上 编译时错误 类型      更新时间:2023-10-16

我有一个模板函数template<class T> T exc(T()),其中T有时可能是void。

此函数用于执行一个函数并返回值(如果不是void)。

这是exc的简化内容(当然我有其他内容=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;});

如您所知,当typeid(T).name()等于"void"时,strcmp返回0

也就是说,运行时在理论上没有问题。然而,这是错误

error C2182 : illegal use of type 'void'

我使用MSVC cl命令行编译器,我认为问题可能是由编译器引起的,该编译器将调用函数的每个模板类型替换为T,因此在T obj时,会出现错误。

我想问一下,有没有其他解决方案?有没有其他方法可以声明obj,以便编译器将其视为"正确"?还是应该用void exc(void (*func)())覆盖exc?

如果您的"实际代码"对模板化类型做了更多的处理,那么重载就是答案

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)();
}

(无论如何,在void的情况下,您将无法显式声明模板参数,专业化可以做到这一点,但要注意一些重载与专业化的解决方案)。

最后,您还可以返回一个void呼叫

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

需要记住的一点是,在编译模板化代码时,所有范围内分支在任何时候都应该是有效的。如果模板化的类型不匹配,则if分支不会神奇地"消除死代码"——它会产生错误。

只需执行:

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

您可以从void函数中returnvoid类型的表达式。

编辑:如果您需要对obj应用特殊处理,请不要专门化您的函数模板。过载:

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

您有错误,因为这两个分支必须是有效的并且

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

对于T == void无效(即使不采取分支)

您可以使用过载来解决您的问题:

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