【问题标题】:Validity of switching on template parameter to improve type safety开启模板参数的有效性以提高类型安全性
【发布时间】:2015-02-22 16:35:22
【问题描述】:

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

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
    }
}

在编译时,我收到编译器警告,因为我没有明确处理 colour == Colour::BLACK 情况。为了安抚编译器,我必须包含 default: // this never happens 之类的内容。

一位同事建议在 Colour 上进行模板化,因为它允许编译器静态确定函数模板永远不会使用无效的枚举值调用:

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
    }
}

在编译时,编译器会在 do_thing_assuming_nonblack_colour&lt;Colour::BLACK&gt;(...) 的实例化时发出警告,因为这种情况在 switch-case 中没有处理。我们可以使用static_assert 更严格地执行此操作。然而,对我来说,这似乎是对模板参数的滥用,因为从逻辑上讲,枚举是函数的参数,此外,switch case 基本上变得无用,因为每个枚举值现在完全由一个单独的函数处理。所以在每个函数中,只有一种情况会触发。

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

【问题讨论】:

  • 将运行时开关与编译时机制混合使用没有多大意义。你会如何在实践中使用这个东西?
  • 对于其他枚举值,您可以将 do_thing_assuming_nonblack_colour(Colour::RED, ...) 替换为 do_thing_assuming_nonblack_colour&lt;Colour::RED&gt;(...),依此类推。
  • 是的,但是您将如何决定调用哪个函数模板实例化?
  • 我不确定我是否理解你的问题......你打电话给适合你想要做的任何事情的任何一个。如果您将形状着色为蓝色,您可以调用colour_shape&lt;Colour::BLUE&gt;(shape)

标签: c++ templates types enums compiler-warnings


【解决方案1】:

如您所见,如果您将 Colour 设为 函数do_thing_assuming_nonblack_colour 而不是 运行时函数参数,每当你写一个调用 do_thing_assuming_nonblack_colour它只能做的事 您在编译代码之前决定的。 如果有时从文件 F 的第 N 行执行函数调用 将对象着色为红色,然后执行该函数调用总是将对象着色为红色。

如果您从内部呼叫do_thing_assuming_nonblack_colour 带有签名的函数 void do_more_complex_thing(Colour colour), 您需要单独致电do_thing_assuming_nonblack_colour 处理可能传递给do_more_complex_thing 的每种颜色。 或者您可以编写专门的模板 do_more_complex_thing,但你很快就会看到 如果你沿着这条路走得很远,就会有大量重复的代码, 让维护这个代码库变得像噩梦一样。

但如果你能忍受Colour参数的约束 do_thing_assuming_nonblack_colour 必须始终在编译时知道, 您可以使用模板特化消除 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
}

除了消除对switch 的需要之外,这种设计还确保 打电话给void do_thing_assuming_nonblack_colour&lt;Colour::BLACK&gt;() 不仅会导致编译器警告; 这将导致编译时错误, 为您提供更好的意外保护 使用参数Colour::BLACK调用此函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    相关资源
    最近更新 更多