朋友没有<>的模板专业化

时间:2013-10-18 21:25:23

标签: c++ templates language-lawyer

C ++ 03和C ++ 11在[temp.friend]的第一段中有:

[编辑引用。首先尝试错过措辞的第二个区别。]

  

对于非模板声明的友元函数声明:

     
      
  1. 如果朋友的姓名是合格或不合格的 template-id ,则朋友声明是指功能模板的特化,否则

  2.   
  3. 如果朋友的名字是 qualified-id 并且在指定的类或命名空间中找到匹配的nontemplate函数,则friend声明引用该函数,否则,

  4.   
  5. [C ++ 03:]如果朋友的名字是 qualified-id ,并且在指定的类或命名空间中找到了函数模板的匹配特化,那么朋友声明是指函数模板专门化,否则,

         

    [C ++ 11:]如果朋友的名字是 qualified-id 并且在指定的类或命名空间中找到匹配的函数模板,那么友元声明是指推导出的该功能模板的专业化,否则,

  6.   
  7. 该名称应为 unqualified-id ,声明(或重新声明)普通(非模板)功能。

  8.   

[措辞的变化看起来像是对我的澄清。虽然我想可能有不同的方法来解释C ++ 03关于“在类或名称空间中找到专业化”的措辞。]

我很好奇第三颗子弹。我编写此代码以尝试匹配其要求,但g ++ 4.8.1和clang ++ 3.4都拒绝代码,无论是使用-std = c ++ 03还是-std = c ++ 11:

template <class T> class R;
namespace N {
    template <class T> void test(const R<T>&);
}

template <class T>
class R {
    friend void N::test(const R<T>&);  // 8
    int m;
};

template <class T>
void N::test(const R<T>& rec) { rec.m; }

int main() {
    R<int> r;
    N::test(r);
}

当然如果我将第8行改为

friend void N::test<>(const R<T>&);

第一颗子弹适用,程序被接受。 g ++打印一个有用的警告,说朋友“声明一个非模板函数”,并建议我可能想要这样做。为了清晰和安全,代码可能会获得更多样式点。

但是上面的代码不应该被第三个子弹覆盖并且有效吗? friend声明不是模板声明,并使用 qualified-id 作为名称,而不是 template-id 。并且没有非模板函数声明来匹配第二个项目符号。

这只是两者共同的编译器错误吗?或者我误解了什么,如果有的话,是否有一个程序的例子确实证明了第三个子弹?

3 个答案:

答案 0 :(得分:1)

在第// 8行, 修改后的代码为: friend void N::test< R<T> >( R<T>&); 也是正确的。

friend void N::test<R<T>>(const R<T>&);//one type is friend with one type  #1
friend void N::test<>(const R<T>&);// one type is friend with one type    #2

我使用了一些代码证明#1等于#2

最后,我试着回答你的问题。我不确定这是对的。

 friend void N::test(const R<T>&);

实例化类R时,R<T>是已知类型。但是,功能是

声明为友元函数并且实际上没有实例化函数模板,那么

朋友功能是一个不存在的功能。从语法的角度来看,

编译器会提示您它是一个函数而不是模板

N::test (r);

在这个地方,函数被实例化,但编译器与

不匹配 在R类声明之前的朋友,因为你没有在R

中声明为模板

类,你只需声明一个函数。

答案 1 :(得分:0)

我认为&lt;&gt;从14.8.2.6开始,是扣除的条件,

  

在declarator-id引用函数模板特化的声明中,执行模板参数推导以识别声明引用的特化。具体而言,这是针对显式实例化(14.7.2),显式特化(14.7.3)和某些朋友声明(14.5.4)而完成的。

在这种情况下,declarator-id不是特化,因此不会发生演绎。

答案 2 :(得分:0)

N :: test是一个模板化函数,它接受一个名为T的类。它不需要一个名为R<T>的类。适当地改变功能,它将起作用。

namespace N
{
    template <class T>
    void test ( const T & );
}

template <class T>
class R
{
    friend void N::test ( const R<T> & );
    int m;
};

template <class T>
void N::test ( const T & rec ) { rec.m; }

int main ( )
{
    R<int> r;
    N::test ( r );
}