如何解决结构对其他结构类型的循环依赖,定义在 header 只有库 (C++) 中?

How to solve circular dependency of structures to types of other structures, defined in a header only library (C++)?

我想写一个转换实用程序 header,它可以毫不费力地使用,所以它应该用作 header-only 库(因为它太小了,创建它会有点过分一个单独的 .lib 无论如何)。

这里是lib的草图(只包含UTF8和UTF16的转换)

namespace cp_utils {
  namespace cp { //codepages
   struct UTF8 {
     typedef std::string string;
     typedef const std::string& string_ref; //will be boost::string_ref later on 

     template<typename ToCP>
     static typename ToCP::string convertTo(string_ref str);

     template<>
     static UTF16::string convertTo<UTF16>(string_ref str) { //<- Problem here!
       //... convert UTF-8 string to UTF-16 wstring
       return L"UTF-16"; //Mock implementation
     }
   };

   struct UTF16 {
     typedef std::wstring string;
     typedef const std::wstring& string_ref;

     template<typename ToCP>
     static typename ToCP::string convertTo(string_ref str);

     template<>
     static UTF8::string convertTo<UTF8>(string_ref str) {
       //... convert UTF-16 wstring to UTF-8 string
       return "UTF-8"; //Mock implementation
     }
   };    

   ///... other codepages similar
  }

  //actual conversion function
  template<typename FromCP, typename ToCP>
  inline typename ToCP::string convert(typename FromCP::string_ref str) {
   return FromCP::convertTo<ToCP>(str);   
  }
}

//usage:
int main() {
  wstring utf16str = convert<cp::UTF8, cp::UTF16>("test");
}

错误消息说 C2065:"UTF16" 未声明的标识符 我试图通过使用简单 struct UTF16; 的 UTF16 结构的前向声明来解决此问题,但随后出现错误状态 C2027:使用未定义类型 "UTF16"。在定义 UTF8 和 vice-versa.

之前,我必须以某种方式提供 UTF16 的完整定义

如果我在结构之外定义 UTF8 和 UTF16 的专用转换函数,那么只要库只在一个 .cpp 文件中使用它就可以正常工作,因为有多个定义,这使得这很不切实际。

我该如何解决这个问题?

PS: 我用MSVS 2013编译代码

转换函数不必是成员。如果你让它们成为自由函数,那么你就不必担心前向声明或循环引用。此外,您甚至不需要函数模板。只需将要转换的内容作为空类型参数传递即可:

struct UTF8 {
    using string = std::string;
};

struct UTF16 {
    using string = std::wstring;
};

// 8 --> 16
UTF16::string convertTo(UTF8::string const& from, UTF16 );

// 16 --> 8
UTF8::string convertTo(UTF16::string const& from, UTF8 );

用法如下:

UTF8::string some_string = ...;
auto as_utf_16 = convertTo(some_string, UTF16{});

这实际上是这个问题 Circular Dependencies / Incomplete Types 和一般 "how do I resolve circular dependencies in C / C++" 问题的副本,只是有点难看,因为涉及到模板。

基本上你应该移动这两个函数的实现

template<>
 static UTF16::string convertTo<UTF16>(string_ref str) { //<- Problem here!
   //... convert UTF-8 string to UTF-16 wstring
   return L"UTF-16"; //Mock implementation
 }


 template<>
 static UTF8::string convertTo<UTF8>(string_ref str) {
   //... convert UTF-16 wstring to UTF-8 string
   return "UTF-8"; //Mock implementation
 }

在 class 个主体中,只留下声明,并将它们放在文件末尾。 (但仍在同一个命名空间中。)