【问题标题】:How to specialize template member function?如何专门化模板成员函数?
【发布时间】:2016-05-03 05:20:16
【问题描述】:

我有以下模板方法:

struct MyStruct
{
  // ...
  template<typename T>
  void readField(std::istream& in, T& data)
  {
      read(in, data);
      data = ntohl(data);
  }
};

template<>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}

但我得到了那些奇怪的链接器错误:

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:62: `void MyStruct::readField(std::basic_istream >&, unsigned 字符&)' ../Lib/obj/MyStruct.o:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/异常: 62: 首先在这里定义 collect2: ld 返回 1 退出状态 make: *** [Lib] 错误 1

我怎样才能专门化这个成员函数?

编辑

这种方法有效:

struct MyStruct
{
  // ...
  template<typename T>
  void readField(std::istream& in, T& data)
  {
    read(in, data);
    data = ntohl(data);
  }

  void readField(std::istream& in, uint8_t& data)
  {
    read(in, data);
  } 
};

或使用inlines 或使用inline在课堂外进行专业化

struct MyStruct
{
  // ...
  template<typename T>
  void readField(std::istream& in, T& data)
  {
      read(in, data);
      data = ntohl(data);
  }
};

template<>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}

【问题讨论】:

  • 函数特化是常规函数,而不是模板。与任何其他函数一样,它必须在头文件中声明并在源文件中实现;否则,在头文件中实现但标记为inline
  • @IgorTandetnik 这种方法有效。您可以将其作为答案提交,我可以接受。虽然我可以在没有inline的头文件中定义这个方法。为什么会这样?
  • I can define this method in the header file without inline 显然你不能,或者你不会在这里提问。尝试时会出现链接器错误,不是吗?也许我误解了你的意思。
  • @IgorTandetnik 好的,我的意思是我可以在没有inline 的类内部的头文件中定义方法(没有任何模板/专业化)。正如你提到的,我能做的是用inline 专门化它,但仅限于类定义之外。非常感谢
  • 成员函数的类内定义隐式为inline

标签: c++ templates member-functions template-function


【解决方案1】:

正如Igor所说,你可以在头文件中实现泛型版本,然后在cpp文件中实现特化,例如:

// MyStruct.h

struct MyStruct {
  // ...
  template <typename T>
  void readField(std::istream& in, T& data) {
    read(in, data);
    data = ntohl(data);
  }
};

然后在cpp文件中就可以实现特化了,例如:

// MyStruct.cpp

template <>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data) {
  read(in, data);
}

更新:读取 cmets 后,特化也可以在与主模板相同的头文件中,但不在结构中,例如(我通过编译和运行类似示例验证了这一点,没有错误):

// MyStruct.h

struct MyStruct {
  // ...
  template <typename T>
  void readField(std::istream& in, T& data) {
    read(in, data);
    data = ntohl(data);
  }
};  

template <>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data) {
  read(in, data);
}

// End MyStruct.h

【讨论】:

  • 在源文件中实现特化时,需要在头文件中声明。如template &lt;&gt; void MyStruct::readField&lt;uint8_t&gt;(std::istream&amp; in, uint8_t&amp; data); 调用代码需要知道特化存在,即使它不需要查看其实际实现。
【解决方案2】:

您可以inline 专门化以避免多个定义。

template<>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}

为了完整起见,您还有一个选择是在 .cpp 文件中创建一个实现,并通过标头导出该实现。

//MyStruct.h

#ifdef MYSTRUCT_EXPORTS
#ifdef __GNUC__
#ifndef __linux__
#define MYSTRUCT_API __attribute__ ((dllexport))
#else
#define MYSTRUCT_API __attribute__ ((visibility ("default")))
#endif
#else
#define MYSTRUCT_API __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#ifndef __linux__
#define MYSTRUCT_API __attribute__ ((dllimport))
#else
#define MYSTRUCT_API __attribute__ ((visibility ("default")))
#endif
#else
#define MYSTRUCT_API __declspec(dllimport)
#endif
#endif

template<>
void MYSTRUCT_API MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data);


//MyStruct.cpp

template<>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}

【讨论】:

  • 这行得通 :) 但我们必须记住,它只适用于类定义之外的专业化
  • @Patryk 是的,我添加了一个关于如何导出实现的示例,它也适用于类定义中的特化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-20
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多