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

时间:2014-09-28 13:39:51

标签: c++ visual-c++ compiler-errors

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

此函数用于执行函数并返回值(如果它不是无效的)。

这是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;});

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

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

error C2182 : illegal use of type 'void'

我使用MSVC cl命令行编译器,我认为这个问题可能是由编译器引起的,它替换了为T调用函数的每个模板类型,所以在T obj,会发生错误。

我想问一下,这有什么替代解决方案吗?有没有其他方法来声明obj,以便编译器将其视为“正确”?或者我应该用void exc(void (*func)())覆盖exc?

3 个答案:

答案 0 :(得分:2)

只是做:

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

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

修改:如果您需要对objdon't specialize your function template进行特殊处理。超载它:

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

答案 1 :(得分:2)

如果您的“实际代码”更多地涉及模板化类型

,则重载是答案
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案例中明确说明模板参数,专业化可以这样做,但请注意to some overloading vs specialization resolutions)。

最后,您还可以返回void来电

void fun() {}

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

exc<void>(fun);

要记住的一件事是,在编译模板化代码时,所有范围内的分支都应该随时有效。如果模板化类型不匹配,则if分支不会被神奇地“消除死代码” - 它将产生错误。

答案 2 :(得分:1)

您有错误,因为两个分支必须有效且

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