【问题标题】:How do I check types within a template class in c++?如何在 C++ 中检查模板类中的类型?
【发布时间】:2020-05-01 11:18:39
【问题描述】:

我有一个可以显示图像或文本行的 Button 类,我正在尝试使用模板实现。

如果是文本,那么模板类型是:const char*

如果是图片,则模板类型为:const wchar_t*

这里是需要区分这两种类型的方法:

template <typename T>
void Button<T>::draw(EasyGraphics* canvas)
{
    canvas->setBackColour(colour);

    if (mouseOver)
    {
        canvas->setPenColour(EasyGraphics::BLACK, 4);
    }
    else
    {
        canvas->setPenColour(EasyGraphics::BLACK, 2);
    }

    canvas->drawRectangle(Entity::GetX(), Entity::GetY(), Entity::getWidth(), Entity::getHeight(), true);
    canvas->setFont(20, L"");
    canvas->setTextColour(textColour);

    switch (typeid(T))
    {
        // Button has display text
        case typeid(const char*):
        {
            canvas->drawText(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3);
            break;
        }
        // Button has display image
        case typeid(const wchar_t*):
        {
            canvas->drawBitmap(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3, 60, 60, 0x0000FF00);
            break;
        }
    }
}

我似乎无法让底部的开关正常工作。我不确定切换是否是最好的方法。任何建议都将不胜感激,干杯。

【问题讨论】:

    标签: c++ templates types switch-statement typechecking


    【解决方案1】:

    使用类型特征(和if constexpr)而不是typeid。例如:

    void g_char(const char*);
    void g_wchar_t(const wchar_t*);
    
    template <typename T>
    void f(T)
    {
        if constexpr (std::is_same_v<T, const char*>)
        {
            g_char(T());
        }
        else if constexpr (std::is_same_v<T, const wchar_t*>)
        {
            g_wchar_t(T());
        }
    }
    

    http://coliru.stacked-crooked.com/a/08e9e66ed5c776a4

    开关在这里不起作用的原因是条件必须隐式转换为整数类型,而std::type_infotypeid 返回的内容)不是。

    但是如果您尝试保留typeid 表达式,当您尝试调用drawTextdrawBitmap 时,您会遇到编译时类型检查的问题。除非您使用 constexpr 分支 (if constexpr),否则这两个调用都必须有效。但是,条件必须是编译时常量,其中不能使用typeid。因此,您可以使用类型特征,特别是 std::is_same

    【讨论】:

    • 我刚刚尝试过,似乎对 const char* 工作正常,但我收到此错误:错误 C2664 'void EasyGraphics::drawBitmap(const wchar_t *,int,int,int,int ,int)':无法使用 [ T=const char * ] Chess Game 将参数 1 从 'T' 转换为 'const wchar_t *'
    • 如果您使用typeid(T) == typeid(const char*) 解决方案,最好使用std::is_same 和constexpr if
    • @tikkrey 谢谢我正要这样做。这是正确的解决方案,因为在 OP 的函数中完成了不同的调用。
    • 应该是else if constexprstackoverflow.com/questions/52356341/…
    • @tikkrey 很高兴知道。看起来是大多数编译器都能容忍的事情之一。
    【解决方案2】:

    做一个模板特化:

    template <typename T>
    void DoDraw(EasyGraphics* canvas);
    
    template<>
    void DoDraw<char>(EasyGraphics* canvas)
    {
      canvas->drawText(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3);
    }
    
    template<>
    void DoDraw<wchar_t>(EasyGraphics* canvas)
    {
      canvas->drawBitmap(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3, 60, 60, 0x0000FF00);
    }
    
    template <typename T>
    void Button<T>::draw(EasyGraphics* canvas)
    {
      ...
      DoDraw(canvas);
    }
    

    *检查模板参数,有const char* 而不仅仅是char 很奇怪。

    【讨论】:

      【解决方案3】:

      您可以谨慎选择 typeid,因为它不适合运行时多态性。例如下面。

      #include <iostream>
      
      template<class T>
      void getType(T A) {
          std::cout<<typeid(A).name()<<"\n";
      }
      
      class Base {
      };
      
      class Derived : public Base {
      };
      
      int main(){
          getType(Base());
          getType(Derived());
          Derived *d = new Derived();
          getType(d);
          Base *b = d;
          getType(b);
          return 0;
      }
      

      输出:

      4Base
      7Derived
      P7Derived
      P4Base
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-18
        • 1970-01-01
        • 2014-03-31
        • 2017-05-08
        • 2016-02-13
        • 1970-01-01
        相关资源
        最近更新 更多