【问题标题】:Specialization of template member functions of a non-template class非模板类的模板成员函数的特化
【发布时间】:2013-12-20 20:56:31
【问题描述】:

我想在 cpp 文件中定义模板函数的显式特化。那可能吗?更具体地说,我有以下代码,编译时没有错误:

//class.h
class myclass
{
public:
    /* Constructor */
    myclass();
    /* Trigger fcn */
    template<typename T> T Trigger(T rn);

private:
    /* Specializations of the templated Trigger(...) function */
    template<> int Trigger<int>(int rn)
    {
        int_do(rn);
    }
    template<> double Trigger<double>(double rn)
    {
        double_do(rn);
    }
}

但是,头文件中的定义对我来说看起来很奇怪,所以我想将定义与声明分开,如下所示:

//class.h
class myclass
{
public:
    /* Constructor */
    myclass();
    /* Trigger fcn */
    template<typename T> T Trigger(T rn);

private:
    /* Specializations of the templated Trigger(...) function */
    template<> int Trigger<int>(int rn);
    template<> double Trigger<double>(double rn);   
}

和:

//class.cpp
/* Specializations of the templated Trigger(...) function */
template<> int myclass::Trigger<int>(int rn)
{
    int_do(rn);
}
template<> double myclass::Trigger<double>(double rn)
{
    double_do(rn);
}

有什么办法吗?

【问题讨论】:

  • 看起来很奇怪并不是 IMO 的充分理由。没有办法做到这一点,不涉及一些妥协,所以我会习惯它。
  • 您的模板定义需要保留在头文件中,但您可以在 class {} 块定义之外(仍然在 .h 文件中)以您的方式声明函数
  • 代码甚至都无法编译...您只能在包含类的命名空间中编写特化。对于两者:GCC:error: explicit specialization in non-namespace scope 'class myclass'。叮当声:error: explicit specialization of 'Trigger' in class scope。你在使用 MSVC 吗?
  • 认为您将显式实例化专业化混入同一个篮子。他们不一样。后者通常提供替代实现,前者提供将实例分配给特定翻译单元的机制。如果您想在指定特定编译单元的同时进行专业化,请参阅下面 Mike 的回答。

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


【解决方案1】:

您唯一的错误是在类中声明了特化。在标题中声明它们,但在类之外:

class myclass
{
public:
    myclass();
    template<typename T> T Trigger(T rn);
};

/* Specializations of the templated Trigger(...) function */
template<> int myclass::Trigger<int>(int rn);
template<> double myclass::Trigger<double>(double rn);   

然后您可以在源文件中定义它们,就像您所做的那样。

请注意,您的第一个 sn-p 无法编译(除非您的编译器具有非标准扩展),因为不能在类中声明特化。

【讨论】:

  • 感谢 Mike,现在可以编译了。顺便说一句,我之前的代码是用 VisualStudio 9.0 编译的,我不知道它是否使用了非标准扩展。
【解决方案2】:

除了之前关于专业定位的回答:

您可以在 .cpp 文件中定义模板函数。这也意味着它们只能在此翻译对象/文件中实例化。 在您的情况下,部分专业化在 .h 中声明,其他编译单元将期望它们的存在。

例如在 文件 tmp.h:

#include <iostream>
class T {
public:
  template <typename T> void foo(const T& t)
  {
    std::cout << "generic foo" << std::endl;
  }
};
// forward declaration of specialization
template<> void T::foo(const double& t);

文件 tmp.cpp:

#include "tmp.h"

template <> void T::foo(const double& t)
{
  std::cout << "double foo" << std::endl;
}

文件 main.cpp:

#include "tmp.h"
int main(int argc, const char** argv)
{
  T t;
  t.foo(1.0); 
  t.foo(1);
  return 0;
}

现在编译两个 .cpp 文件都可以正常工作:

g++ main.cpp tmp.cpp -o tmp
./tmp
double foo
generic foo

没有专业化的定义:

g++ main.cpp -o tmp
/tmp/ccpCJr3B.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `void T::foo<double>(double const&)'
collect2: error: ld returned 1 exit status

【讨论】:

  • 这不是我要问的,但非常有用。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-10
  • 1970-01-01
相关资源
最近更新 更多