C ++中非模板类的专用成员函数

时间:2011-05-20 19:53:03

标签: c++ templates dependent-name

我正在尝试使用模板化参数来专门化非模板类的模板成员函数:

#include <array>
class C
{
public:
  template<class Container>
  void Foo( Container& )
  {
    // ...
  }
};

template<class T, std::size_t N>
template<>
void C::Foo< std::tr1::array<T,N> >( std::tr1::array<T,N>& )
{
  // special
}

我收到错误“非法使用显式模板参数”。什么是使这个有效的正确语法?


更新

也许我过度简化了这个问题。我真正想做的是专门处理这个案例,其中涉及一个从属名称,我认为这可能是什么在这里投入一个猴子扳手。我最初的想法是重载这个功能:

class C
{
public:
  template<class Iter>
  void Foo( Iter )
  {
    std::cout << "Normal\n";
  }

  template<class T, std::size_t N>
  void Foo( typename std::tr1::array<T,N>::iterator )
  {
    std::cout << "Special\n";
  }
};

int main()
{
  C c;
  std::tr1::array<int,10> a1;
  c.Foo( a1.begin() ); // Doesn't print "Special"!
}

但特殊的Foo没有被调用。我怎么能这样做?

2 个答案:

答案 0 :(得分:2)

只有成员函数是模板化的,这意味着你只应该使用一个template<...>。但这也无法解决,因为你不能部分专门化一个功能。

处理问题的常用方法是通过重载,而不是专门化(模板函数的专业化没有那么有用)。

struct test {
   template <typename Container>
   void f( Container& ) { ... }

   template <typename T, int N>
   void f( std::array<T,N>& ) { ... }
};

请注意,不同之处在于它们是两个独立的模板函数(而非专业化)。

编辑:更新后

问题的更新完全改变了问题。您看到的问题是第二个版本的参数是一个从属名称,因此它是不可推导的。给定函数调用,编译器无法确定什么类型T,并且整数常量N与该特定实例化相匹配。考虑一个不同的例子:

template <typename T>
struct inner_int {
   typedef int type;
};
template <typename T>
void foo( typename inner_int<T>::type ) {
}
int main() {
   foo( inner_int<double>::type() );
}

当编译器在main中处理调用时,它实例化模板并从中创建一个临时的类型,然后它尝试决定如何处理foo但是在那个时间它只知道用int rvalue调用它...原来的inner<double>::type已经消失了,现在它只是foo( int() )而且编译器必须尝试实例化{{ 1}}用所有可能的类型来确定它们是否适合,在更糟糕的情况下,如上所述,很多都匹配。

答案 1 :(得分:1)

部分功能模板专业化是非法的。从C ++ 03标准,§14/ 2:

  

template-declaration 只能作为命名空间范围或类范围声明出现。在函数模板声明中, declarator-id 应为 template-name (即,不是 template-id )< / strong>即可。 [注意:在类模板声明中,如果类名是 template-id ,则声明声明类模板部分特化。]

您只想简单地重载您的功能:

class C
{
public:
    template<typename Container>
    void Foo(Container&)
    {
        // ...
    }

    template<typename T, std::size_t N>
    void Foo(std::tr1::array<T, N>&)
    {
        // special
    }
};

编辑(响应OP的编辑):

如果您只是针对此特定方案寻找解决方法,因为std(::tr1)::array<T,N>::iterator只是T*,您的'特殊'重载可以是:

template<typename T>
void Foo(T*&)
{
    // special
}