【问题标题】:Template specialization works fine with gcc but not with visual studio 10模板专业化适用于 gcc 但不适用于 Visual Studio 10
【发布时间】:2013-09-10 15:12:08
【问题描述】:

我的代码中有这个模板专业化,当我用 gcc 编译它时,它工作得非常好,但当我使用 Visual Studio 10 的编译器编译它时却没有:

Field.cpp

template<>
void Field<std::string>::setValueString(const std::string &val)
{
  operator=(val);
}

template<>
void Field<bool>::setValueString(const std::string &val)
{
  bool v = static_cast<bool>(atoi(val.c_str()));
  operator=(v);
}

template<>
void Field<int32_t>::setValueString(const std::string &val)
{
  int intv = atoi(val.c_str());
  operator=(intv);
}

template<>
void Field<int16_t>::setValueString(const std::string &val)
{
  int intv = atoi(val.c_str());
  operator=(intv);
}

Field.hpp

template<typename FieldType>
class Field : public FieldBase
{
public:
  Field(const std::string &fieldName)
    : FieldBase(fieldName), _overriddenInsertValue(this) {}
  ~Field() {}

  (...)

  /**
   * @brief Template specialized for every available field type in Model.cpp
   */
  void setValueString(const std::string &)
  {
    ALT_ERROR("Field::setValueString called with wrong argument type.");
  }
};

由于某种原因,在 Windows 上,我总是遇到错误,但我不明白为什么,因为当我使用 gcc 在 linux/mac os 上运行它时,它工作正常。

【问题讨论】:

  • 错误到底是什么意思?
  • 很遗憾,但如今(C++11 被广泛实施/使用,C++14 准备就绪)MSVC 并不是与 C++ 一起工作的最佳编译器之一。如果有人不同意,请阅读 VS2013 路线图:听起来很糟糕。
  • 错误是我最终使用了默认的 SetValueString 函数(“使用错误的参数类型调用”),而不是我应该使用的特殊情况。当我将专业化移动到头文件时,它终于可以正常工作了,这有多奇怪?
  • @Damien T:将这些特化移动到头文件的唯一方法是使所有函数内联。同时,看起来在您的原始代码中您不想将它们内联。如果您不想使它们内联,那么它们必须.cpp 文件中定义,否则您将出现链接器错误。同样,正如答案中所述,您可能只是忘记在代码的原始版本中声明您的专业化。

标签: c++ visual-studio-2010 templates gcc template-specialization


【解决方案1】:

如果您想在.cpp 文件中定义您的模板特化,您仍然必须在头文件中声明您的所有模板特化

template<> void Field<std::string>::setValueString(const std::string &val);
template<> void Field<bool>::setValueString(const std::string &val);
template<> void Field<int32_t>::setValueString(const std::string &val);
template<> void Field<int16_t>::setValueString(const std::string &val);

上述声明必须存在于头文件中。我在您的代码中没有看到它们。

您不能只在某个 .cpp 文件中专门化模板,然后期望编译器以某种方式神奇地在所有其他翻译单元中了解它。这就是头文件中声明的用途。

【讨论】:

  • 好的,谢谢。当我使用 gcc 作为编译器时,我很惊讶它在 mac os/red hat 上运行良好。
  • @Damien T:一定是 gcc 实现的一些特殊性。
【解决方案2】:

我认为要正确专门化 Field.cpp 中函数的实现,您需要首先在 Field.hpp 中声明这些函数。

要专注于一个类型,你需要这样的东西:

template<>
class Field <int32_t> : public FieldBase
{
public:
  ... rest of the functions
  void setValueString(const std::string &);
};

希望这会有所帮助, 拉克斯万。

【讨论】:

  • OP 想要专门化个别成员函数。您的示例显示了如何专门化整个类,这是完全不同的事情。
  • 是的,但是您仍然需要通过专门化整个类型来声明函数,我认为这是一种更好的做法,因为您没有神秘的声明(如模板 void Field::setValueString(const std::string &val);) 用于最终执行意外操作的特定类型。如果在团队中工作可能会令人困惑。
  • 专业化整个类和专业化个别功能是完全不同的事情,服务于不同的目的。后者可能可以用前者代替,但它可能导致大量代码重复(即,必须为每个专业重新定义整个类)。我不明白这一点。而且我不明白“令人困惑”和“团队”与它有什么关系。
猜你喜欢
  • 2014-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多