bcc32:专注于 `std::vector<bool>` 时出现奇怪错误

bcc32: strange error when specialising on `std::vector<bool>`

classic 32 位 Borland/Embarcadero 编译器 - a.k.a。 bcc32 - 当特征 class 专用于 std::vector<bool> 时,会出现奇怪的故障。特别是,它无法编译专业化的用法,因为它没有找到它的任何成员。对于其他类型——比如 std::vector<char>——完全没有问题。使用 BC++ 5.5.1(免费)和 BC++ 7.1 (RX/Seattle) 进行测试。

有解决办法吗?

#include <iostream>
#include <typeinfo>
#include <vector>

template<typename T>
struct traits {  };

template<> struct traits< std::vector<char> >
{
   enum {  ENUM = 42  };

   static int func ()  {  return ENUM;  }
};

template<> struct traits< std::vector<bool> >
{
   enum {  ENUM = 666  };

   static int func ()  {  return ENUM;  }
};

///////////////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
void test ()
{
   typedef traits<T> TT;

   // separate lines to see exactly where the compiler barfs
   std::cout << typeid(T).name();
   std::cout << " " << TT::ENUM;        // E2451 Undefined symbol 'ENUM'
   std::cout << " " << TT::func();      // E2451 Undefined symbol 'func'

   TT tt;
   std::cout << " " << tt.ENUM;         // E2316 'ENUM' is not a member of 'traits<std::_Bvector>'
   std::cout << " " << tt.func();       // E2316 'func' is not a member of 'traits<std::_Bvector>'
   std::cout << "\n";
}

int main ()
{
   test< std::vector<char> >();
   test< std::vector<bool> >();
   return 0;
}

注意:在某些情况下可能有用的 变通方法 是将 vector<bool> 的特化编码到主模板中(通常未定义) );然后可以像往常一样完成其他类型的特化,即使使用 bcc32,代码也能按预期工作。

运行时断言可以验证特征模板的唯一非专用化身是 std::vector<bool> 的化身。使用特征的模板将在方便的地方调用断言代码(也可以是静态函数)。

template<typename T>
struct traits
{
   // specialisation for std::vector<bool> coded here...
   enum {  ENUM = 666  };

   static int func ()  {  return ENUM;  }

   static void assert_only_vector_bool_not_specialised ()
   {
      assert(typeid(T) == typeid(std::vector<bool>));
   }
};

struct traits_specialisation_base
{
   static void assert_only_vector_bool_not_specialised ()
   {
   }
};

template<> struct traits< std::vector<char> >: traits_specialisation_base
{
   enum {  ENUM = 42  };

   static int func ()  {  return ENUM;  }
};

// ...

template<typename T>
struct UsingTraits
{
   typedef traits<T> TT;

   UsingTraits ()
   {
      TT::assert_only_vector_bool_not_specialised();
   }
};

// ...

UsingTraits< std::vector<char> > erna;
UsingTraits< std::vector<bool> > fred;

std::std::vector<bool> 有点可疑,所以您需要改用 std:: 类型。只需更改为:

#include <iostream>
#include <typeinfo>
#include <vector>
//---------------------------------------------------------------------------
template<typename T> struct traits
    {
    // this is safe constructor/destructor for Borland BDS2006 and later
    traits(){};
    traits(traits& a){};
    ~traits(){};
    traits* operator = (const traits *a){};
    //traits* operator = (const traits &a){}; // use this only if you have dynamic allocation members
    };

template<> struct traits< std::vector<char> >
    {
    enum {  ENUM = 42  };
    static int func ()  {  return ENUM;  }
    };

template<> struct traits< std::_Bvector >   // here use the std type directly
    {
    enum {  ENUM = 666  };
    static int func ()  {  return ENUM;  }
    };
//---------------------------------------------------------------------------
template<typename T> void test ()
    {
    typedef traits<T> TT;

    // separate lines to see exactly where the compiler barfs
    std::cout << typeid(T).name();
    std::cout << " " << TT::ENUM;        // E2451 Undefined symbol 'ENUM'
    std::cout << " " << TT::func();      // E2451 Undefined symbol 'func'

    TT tt;

    std::cout << " " << tt.ENUM;         // E2316 'ENUM' is not a member of 'traits<std::_Bvector>'
    std::cout << " " << tt.func();       // E2316 'func' is not a member of 'traits<std::_Bvector>'
    std::cout << "\n";

    // can ignore this ... it is just output to memo I do not use console
    AnsiString s="";
    s=s+typeid(T).name() + "\n";
    s=s+" " + AnsiString( TT::ENUM ) + "\r\n";        // E2451 Undefined symbol 'ENUM'
    s=s+" " + AnsiString( TT::func() ) + "\r\n";      // E2451 Undefined symbol 'func'
    s=s+" " + AnsiString( tt.ENUM ) + "\r\n";         // E2316 'ENUM' is not a member of 'traits<std::_Bvector>'
    s=s+" " + AnsiString( tt.func() ) + "\r\n";       // E2316 'func' is not a member of 'traits<std::_Bvector>'
    Form1->mm_log->Lines->Add(s);
    }
//---------------------------------------------------------------------------
// this is your main()
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    test< std::vector<char> >();
    test< std::vector<bool> >();
    }
//---------------------------------------------------------------------------

我使用 windows 表单应用程序,所以请忽略表单内容。 constructors/destructors 不是编译所必需的,但由于 Borland BDS2006 和后来的 C++ 引擎 错误,您应该添加它们。有关详细信息,请参阅:

  • BDS 2006 C hidden memory manager conflicts

上面的代码给出了这个输出:

std::vector<char,std::allocator<char> >
 42
 42
 42
 42

std::vector<std::allocator<bool> >
 666
 666
 666
 666