首页 > 解决方案 > C++ 枚举类作为可变模板参数

问题描述

我试图通过使用枚举类作为模板参数在编译时优化一些函数。

比如说

enum class Color { RED, BLACK };

现在,我想定义一个方法

void myMethod<Color c> () {
 if( c == Color::RED ) { ... }
 if( c == Color::BLACK ) { ... }
}

而且我希望编译器myMethod在优化期间制作 2 个副本并消除死代码(它适用于 CUDA 内核,因此速度和寄存器的使用对我来说很重要)

但是,似乎当我使用

void doSomething( const Color c ) {
 myMethod<c>();
}

MSVC 抱怨“表达式必须有一个常量值”。我期望编译器足够聪明,可以myMethod用枚举的每个可能版本编译一个版本。不是这样吗?我可以在没有丑陋的开关的情况下强制它doSomething吗?

谢谢你的帮助 !

标签: c++templatesenums

解决方案


您必须决定运行时 vc 编译时。编译时版本可以是这样的:

enum class Color { RED, BLACK };

template < Color c>  
void myMethod () {
    if constexpr ( c == Color::RED ) { std::cout << "RED" << std::endl; }
    if constexpr ( c == Color::BLACK ) { std::cout << "BLACK" << std::endl; }
}   

int main()
{   
    myMethod<Color::RED>( );
    myMethod<Color::BLACK>( );
}

但是如果你想在运行时切换到编译时生成的特化,你必须切换所有可能的值:

enum class Color { RED, BLACK };

template < Color c>  
void myMethod () {
    if constexpr ( c == Color::RED ) { std::cout << "RED" << std::endl; }
    if constexpr ( c == Color::BLACK ) { std::cout << "BLACK" << std::endl; }
}

void RuntimeDispatch( Color c ) 
{
    if ( c == Color::RED ) { myMethod<Color::RED>(); }
    if ( c == Color::BLACK ) { myMethod<Color::BLACK>(); }
}   

int main()
{   
    RuntimeDispatch( Color::RED );
    RuntimeDispatch( Color::BLACK );
}

根本没有办法将运行时变量用作模板参数,因为它根本不是编译时常量。

如果您必须使用较旧的编译器,则可以constexpr if用模板专业化替换:

template < Color c> void myMethod ();

template <> void myMethod< Color::RED >() { std::cout << "RED" << std::endl; }
template <> void myMethod< Color::BLACK >() { std::cout << "BLACK" << std::endl; }

推荐阅读