C++ 打开模板参数以提高类型安全性的有效性

C++ 打开模板参数以提高类型安全性的有效性,c++,templates,types,enums,compiler-warnings,C++,Templates,Types,Enums,Compiler Warnings,我有一个函数,它将枚举值和其他组合值作为参数。根据枚举的值,该函数以不同的方式操纵其他参数。我知道函数不能用一个或多个潜在的枚举值调用。例如: enum class Colour { RED, GREEN, BLUE, BLACK}; // Pre: colour != Colour::BLACK void do_thing_assuming_nonblack_colour(Colour colour, /*other args*/) { assert(colour != Colour

我有一个函数,它将枚举值和其他组合值作为参数。根据枚举的值,该函数以不同的方式操纵其他参数。我知道函数不能用一个或多个潜在的枚举值调用。例如:

enum class Colour { RED, GREEN, BLUE, BLACK};

// Pre: colour != Colour::BLACK
void do_thing_assuming_nonblack_colour(Colour colour, /*other args*/) {
    assert(colour != Colour::BLACK);
    switch (colour) {
        case Colour::RED:   // do thing A
        case Colour::GREEN: // do thing B
        case Colour::BLUE:  // do thing C
    }
}
在编译时,我得到一个编译器警告,因为我没有显式处理
color==color::BLACK
案例。为了安抚编译器,我必须包含类似于
default://这永远不会发生

一位同事建议在
color
上设置模板,因为它允许编译器静态地确定从未使用无效的枚举值调用函数模板:

template<Colour colour>
void do_thing_assuming_nonblack_colour(/*other args*/) {
    switch (colour) {
        case Colour::RED:   // do thing A
        case Colour::GREEN: // do thing B
        case Colour::BLUE:  // do thing C
    }
}
模板
void do\u thing\u假设颜色为非黑色(/*其他参数*/){
开关(彩色){
外壳颜色::红色://做一件事
外壳颜色:绿色://做某事B
外壳颜色::蓝色://做事情C
}
}
在编译时,编译器将在实例化
do\u thing\u假设颜色为非黑色(…)
时发出警告,因为这种情况不在开关情况下处理。我们可以通过
static\u assert
更严格地执行这一点。然而,在我看来,这似乎是滥用模板参数,因为从逻辑上讲,枚举是函数的一个参数,而且开关情况基本上变得无用,因为每个枚举值现在完全由一个单独的函数处理。因此,在每个函数中,只有一种情况会触发


这是推荐(或至少有效)使用的模板参数吗?

如您所观察到的,如果您将
颜色
作为 函数
做某事\u假设非黑色\u颜色
而非黑色 运行时函数参数,无论何时编写对
做事情\u假设非黑色\u颜色
它只能做事情 这是您在编译代码之前决定的。 如果有时从文件F的第N行执行函数调用 将对象涂成红色,然后执行该函数调用始终将对象涂成红色

如果您从内部调用
do\u thing\u假设颜色为非黑色
具有签名的函数,如
void做更复杂的事情(颜色)
, 您需要单独呼叫
do\u thing\u successing\u non black\u color
要处理可能传递给
的每种颜色,请执行更复杂的操作
。 或者你也可以为它编写专门的模板
做更复杂的事情
,但你很快就会发现 如果沿着这条路走得很远,就会出现大量重复代码, 使维护这个代码库成为噩梦

但是如果你能接受
颜色
参数 假设在编译时必须始终知道非黑色颜色,则, 您可以使用模板专门化消除switch语句:

template <Colour> void do_thing_assuming_nonblack_colour();

template <> void do_thing_assuming_nonblack_colour<Colour::RED>() {
  // do thing A
}
template <> void do_thing_assuming_nonblack_colour<Colour::GREEN>() {
  // do thing B
}
template <> void do_thing_assuming_nonblack_colour<Colour::BLUE>() {
  // do thing C
}
template void do_thing_假设非黑色颜色();
模板无效做某事假设非黑色颜色(){
//做事
}
模板无效做某事假设非黑色颜色(){
//做B件事
}
模板无效做某事假设非黑色颜色(){
//做C件事
}
除了不需要
开关
,这种设计还确保 调用
void do\u thing\u假设颜色为非黑色()
不仅会引起编译器警告; 它将导致编译时错误, 为您提供更好的保护,防止意外伤害
使用参数
color::BLACK

调用此函数将运行时开关与编译时机制混合使用没有多大意义。你在实践中如何使用这个东西?你将用
do\u thing\u suggestion\u nonblack\u color(color::RED,…)
替换
do\u thing\u suggestion\u nonblack\u color(…)
等等作为其他枚举值。是的,但是你如何决定调用哪个函数模板实例化?我不确定我是否理解你的问题。。。无论你想做什么,你都可以打电话给合适的人。如果你把一个形状涂成蓝色,你会叫
color\u shape(形状)