【问题标题】:C++ enum class as a variable template parameterC++ 枚举类作为可变模板参数
【发布时间】:2020-02-26 08:50:39
【问题描述】:

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

举个例子

enum class Color { RED, BLACK };

现在,我想定义一个方法

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

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

但是,似乎当我使用

调用该方法时
void doSomething( const Color c ) {
 myMethod<c>();
}

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

感谢您的帮助!

【问题讨论】:

  • 如果它依赖于非常量变量,您必须在运行时决定要调用哪个myMethod&lt;Color&gt;()。所以,你又回到了switch()(或 if-else-cascade,或将颜色映射到函数指针的数组,或其他)。
  • 这似乎最近经常发生。 const 不会生成(编译时)常量表达式,即可以在编译时计算的表达式。
  • 简而言之:模板=编译时,普通函数参数=运行时。你可以混音,但是你需要定义如何混音,例如已经提到的用一个开关来选择调用哪个函数
  • 很公平,但与 const 表达式无关,我仍然认为编译器会以某种方式读出我的枚举并在运行时根据参数的值做出决定。好吧,也许我期望太高了......谢谢你的帮助:)
  • 您可能想要实现的目标,我曾经申请一个有趣的项目,将ifs 从最内部的循环移到外部。当然,必须为每种情况重新实现嵌套循环。在那里,我使用了带有值的模板参数来防止代码重复。 the templatecall of that template 和一点解释Optimization Attempts

标签: c++ templates enums


【解决方案1】:

你必须决定运行时 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; }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    相关资源
    最近更新 更多