【问题标题】:How to check for the type of a template parameter?如何检查模板参数的类型?
【发布时间】:2012-11-18 03:52:42
【问题描述】:

假设我有一个模板函数和两个类

class animal {
}
class person {
}

template<class T>
void foo() {
  if (T is animal) {
    kill();
  }
}

如何检查 T 是否为动物?我不想拥有 在运行时检查的东西。谢谢

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    使用is_same:

    #include <type_traits>
    
    template <typename T>
    void foo()
    {
        if (std::is_same<T, animal>::value) { /* ... */ }  // optimizable...
    }
    

    不过,通常情况下,这是一个完全不可行的设计,而你真的想要专业化

    template <typename T> void foo() { /* generic implementation  */ }
    
    template <> void foo<animal>()   { /* specific for T = animal */ }
    

    另请注意,具有显式(非推导)参数的函数模板是不常见的。这并非闻所未闻,但通常有更好的方法。

    【讨论】:

    • 谢谢!实际上他们共享了很多代码,所以我不能真正复制它
    • @WhatABeautifulWorld:您始终可以分解您的代码,以便将依赖于类型的部分降级为可专门化的函数...
    • 快速跟进,如果我确实使用 std::is_same,那么它不会减慢其他模板参数的代码,对吧?
    • @WhatABeautifulWorld:特征值都是静态已知的。不应该有任何运行时成本,只要你的编译器是半体面的。不过,如果有疑问,请检查组件。
    • @AdriC.S.:由于没有推断出T,因此您无能为力。您可以保留未实现的主模板并创建一个特化,或者您可以使用is_same 添加一个静态断言。
    【解决方案2】:

    我认为今天,它更好用,但仅限于 C++17。

    #include <type_traits>
    
    template <typename T>
    void foo() {
        if constexpr (std::is_same_v<T, animal>) {
            // use type specific operations... 
        } 
    }
    

    如果在没有constexpr 的 if 表达式主体中使用某些类型特定的操作,则此代码将无法编译。

    【讨论】:

    • 您能否详细说明为什么这样做更好?是性能还是平台相关?
    • 确实有效。泰!
    • @serup 更好,因为它是新的,而旧的东西总是更糟。 inline constexpr bool is_same_v = is_same&lt;T, U&gt;::value;我不知道他们为什么不断添加这些毫无意义的“帮手”,这些帮手只会让人们感到困惑,而不是修复他们破碎的语言。
    【解决方案3】:

    您可以根据传递给其参数的内容来专门化您的模板,如下所示:

    template <> void foo<animal> {
    
    }
    

    请注意,这会根据作为T 传递的类型创建一个全新的函数。这通常是可取的,因为它可以减少混乱,并且本质上是我们首先拥有模板的原因。

    【讨论】:

    • 嗯。这种方法真的是专门化模板参数的唯一可取方法吗?假设我需要在模板函数中管理 10 个不同的子类。我真的必须为各个类编写 10 个不同的模板函数吗?我想我可能错过了这里的核心点。
    • 如果有人不想使用 type_traits,这听起来确实是个好主意。就像有人提到的那样,主要逻辑可以在不同的函数中完成,它接受一个额外的标志来指示类型,并且这个专门的声明可以相应地设置标志并直接传递所有其他参数而无需触及任何东西。所以如果需要处理 10 个不同的类,那么 10 个不同的函数定义基本上就是 10 行。但是如果有超过 1 个模板变量,这会变得很复杂。
    【解决方案4】:

    在 C++17 中,我们可以使用变体

    要使用std::variant,您需要包含标题:

    #include <variant>
    

    之后,您可以像这样在代码中添加std::variant

    using Type = std::variant<Animal, Person>;
    
    template <class T>
    void foo(Type type) {
        if (std::is_same_v<type, Animal>) {
            // Do stuff...
        } else {
            // Do stuff...
        }
    }
    

    【讨论】:

    • T 和 Type 是如何连接的?
    • 这个答案在几个方面存在问题。除了实际错误(typeType 类型的值或此处没有意义的模板)is_same_vvariant 的上下文中没有意义。对应的“特质”是holds_alternative
    • std::variant 在这里完全没有必要
    【解决方案5】:

    std::is_same() 仅从 C++11 开始可用。对于 C++11 之前的版本,您可以使用 typeid():

    template <typename T>
    void foo()
    {
        if (typeid(T) == typeid(animal)) { /* ... */ }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      相关资源
      最近更新 更多