【问题标题】:How do I check my template class is of a specific classtype?如何检查我的模板类是否属于特定的类类型?
【发布时间】:2010-02-15 10:54:16
【问题描述】:

在我的模板化函数中,我试图检查类型 T 是否属于特定类型。我该怎么做?

p/s 我知道模板规范的方式,但我不想这样做。

template<class T> int foo(T a) {
  // check if T of type, say, String?
}

谢谢!

【问题讨论】:

  • 为什么不要“模板规范方式”?
  • 使用“模板重载方式”:)
  • 你可能应该检查行为,而不是类型。
  • 嗯,因为在“规范”部分之前,我有很大一部分相同的代码。
  • 如果您需要检查 T 的类型,您使用模板的方式错误。我认为您应该重新考虑您的方法。

标签: c++ templates


【解决方案1】:

使用特化代替检查类型。否则,不要使用模板。

template<class T> int foo(T a) {
      // generic implementation
}
template<> int foo(SpecialType a) {
  // will be selected by compiler 
}

SpecialType x;
OtherType y;
foo(x); // calls second, specialized version
foo(y); // calls generic version

【讨论】:

  • 专门化函数模板通常是个坏主意;不支持部分特化,如果你混合特化和重载,你经常会得到意想不到的结果。只是从一开始就超载。
【解决方案2】:

如果你不关心编译时间,你可以使用boost::is_same

bool isString = boost::is_same<T, std::string>::value;

从 C++11 开始,它现在是标准库的一部分

bool isString = std::is_same<T, std::string>::value

【讨论】:

  • 备案:is_same 现在是标准库的一部分。
  • "如果你不关心编译时间" 你是指编译代码所花费的时间,还是能够在编译时检测到“相同性”?
【解决方案3】:

嗯,因为我有很大一部分 相同的代码,直到“规范” 部分。

您可以使用重载,但如果大部分代码适用于任何类型,您可能会考虑将不同部分提取到单独的函数中并重载。

template <class T>
void specific(const T&);

void specific(const std::string&);

template <class T>
void something(const T& t)
{
    //code that works on all types
    specific(t);
    //more code that works on all types
}

【讨论】:

    【解决方案4】:

    我想你可以使用 typeid 运算符返回的std::type_info

    【讨论】:

    • 在我看来这就是我所需要的。非常感谢!会试一试
    • 警告:运行时检查。因此,您不能依赖编译时属性。例如。在检查是否 T==std::string 之后,您不能只使用 operator[]
    • @huy 通常最好对类型进行静态检查而不是运行时检查。因此,std::is_samestd::is_convertible 或类似名称。然后您可以避免检查类型的运行时成本。相反,如果只有部分代码需要知道类型,请使用 if constexpr (C++17) 或辅助函数;如果您的所有代码都这样做,请使用函数重载。
    【解决方案5】:

    我怀疑有人应该告诉你为什么避免使用重载或专业化可能不是一个好主意。考虑:

    template<class T> int foo(T a) {
      if(isAString<T>()) {
        return a.length();
      } else {
        return a;
      }
    }
    

    您可能第一眼就认为它也适用于int,因为它只会尝试调用length 来获取字符串。但这种直觉是错误的:编译器仍然检查字符串分支,即使在运行时没有采用该分支。如果T 是一个int,它会发现你正在尝试调用非类的成员函数。

    这就是为什么如果你需要不同的行为你应该分开代码。但是最好使用重载而不是专门化,因为更容易了解事情是如何工作的。

    template<class T> int foo(T a) {
      return a;
    }
    
    int foo(std::string const& a) {
      return a.length();
    }
    

    您还可以更好地分离不同行为路径的代码。这不再是一回事了。请注意,通过重载,参数可能具有不同的类型形式,如果两者匹配得很好,编译器仍将使用正确的版本,就像这里的情况一样:一个可以是引用,而另一个不能。

    【讨论】:

    • 我遇到了你之前提到的问题,这就是为什么我想找到一种解决方法,但不需要重载或类专业化。我没有想到“了解事情将如何运作”部分。会重新考虑,谢谢!
    • 用演员表修改你的例子就可以了。但这仍然不是我最喜欢的解决方案:)
    • @Ben,你是什么意思?在哪里插入演员表?你的意思是写reinterpret_cast&lt;string*&gt;(&amp;i)-&gt;length() 吗?我同意那将是非常丑陋的。如果Tstd::string,它仍然会在另一个分支中失败,因为它无法将其转换为int(返回类型)。也不在我最喜欢的解决方案附近:) 最好重载或专门化它。
    • 这就是 C++17 if constexpr 的用途
    • @DanielH 不幸的是,if constexpr 在撰写此答案时不在。所以说“if constexpr can now 用于使第一个示例有效”会更正确。虽然也许这应该是另一个答案,而不仅仅是评论?
    【解决方案6】:

    如果您真的想避免专业化,可以使用type_traits (available in Boost and TR1)(例如is_sameis_convertible)进行检查。

    【讨论】:

      【解决方案7】:

      您可以对收到的类型执行静态检查(查看 boost 类型特征库),但除非您在某处使用专门化(或 @litb 正确指出的重载),否则您不会能够根据参数类型提供不同的具体实现。

      除非您有特殊原因(您可以添加到问题中)不使用界面中的专业化,否则只需进行专业化。

      template <> int subtract( std::string const & str );
      

      【讨论】:

        【解决方案8】:

        如果您使用的是 C++11 或更高版本,std::is_same 完全符合您的要求:

        template <typename T>
        constexpr bool IsFloat() { return std::is_same<T, float>::value; }
        
        template <typename T>
        void SomeMethodName() {
          if (IsFloat<T>()) {
            ...
          }
        }
        

        http://en.cppreference.com/w/cpp/types/is_same

        【讨论】:

          猜你喜欢
          • 2016-08-07
          • 2011-03-21
          • 1970-01-01
          • 1970-01-01
          • 2014-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多