2016-07-15 98 views
0

我面临的情况是出现了两个有关ADL和模板功能专业化在某些情况下如何工作的问题。模板函数在类模板中的明确的朋友专业化

  1. 为什么我不能用COUT朋友专业化的定义里面? 在这种情况下我收到一个链接错误,指出basic_stream未定义,但如果我切换到调用cat编译继续。

    template<class T> 
    void func1(T&){ 
        ... 
    } 
    
    void cat(){ cout << "foo.func1" <<endl; } 
    
    namespace first{ 
        template<class R> 
        struct foo{ 
         friend void func1<>(foo<int>&){ 
          cout << "foo.func1" <<endl; // cat(); 
         }   
        };  
    } 
    
    foo<int> f; 
    func1(f); 
    
  2. 为什么ADL当我改变专业化指模板类PARAM不适? 如果我对ADL技工没有任何错误,为了解决func1在3中调用的正确版本(例如global(1)或friend defined one(2)),它会收集所有可能的匹配并选择最具体的一。而且,我认为最具体的一个是版本func1,因为不是将函数参数指定为完全依赖于模板参数,而是指定具体类型foo,其中func1不在1中,但ADL选择func1无论如何。这是为什么 ?

    template<class T> 
    void func1(T&){  // 1 
        ... 
    } 
    
    namespace first{ 
        template<class R> 
        struct foo{ 
         friend void func1<>(foo<R>&){  // 2 
          cout << "foo.func1" <<endl; 
         }   
        };  
    } 
    
    foo<int> f; 
    func1(f);  // 3 
    
+0

你的意思是'第一:: foo的 F; '? – aschepler

+0

我不认为这段代码有效。我得到了“错误:在朋友声明中定义显式专门化'func1'”。 http://coliru.stacked-crooked.com/a/728b83afb9b416a4 – aschepler

+0

代码不应该编译,你使用的编译器是什么? – Barry

回答

1

模板参数无关与朋友的声明。你需要随身携带他们在friend声明消除歧义:

template<class R> 
struct foo{ 
    template<typename U> 
    friend void func1<U>(foo<U>&){ 
     cout << "foo.func1" <<endl; // cat(); 
    }   
};  

也为你的情况,你应该决定,如果你想要把如上内联朋友定义,或者只是提供了一个声明:

template<class R> 
struct foo{ 
    template<typename U> 
    friend void ::func1<U>(foo<U>&); 
};  

后者应明确匹配在全局命名空间的friend模板功能,并可以根据需要进行专业化:

template<> 
void func1(int&){ 
    // ... 
} 

template<> 
void func1(std::string&){ 
    // ... 
} 

// a.s.o. 
+0

我相信你的第一个例子是不合格的,ndr。 – Barry

+0

谢谢,从模板类param中分离好友声明参数使其有效。 – xhamr

+0

@巴里,是的,它是部分的,但将部分“func1 ”更改为“func1”,并保留其他部分原样,修复“无部分专业化错误”的问题,这是你所指的。 – xhamr

1

你不需要提供func1的专业化。只需提供过载:

namespace first { 
    template <class R> 
    struct foo { 
     friend void func1(foo&){ 
      std::cout << "foo.func1" << std::endl; 
     } 
    }; 
} 

int i; 
first::foo<int> f; 

func(i); // calls ::func<int> 
func1(f); // calls first::func1(first::foo<int>&); 

否则,你可以朋友specizliation,但你不能定义在类体内专业化:

template <class R> 
struct foo { 
    friend void func1<>(foo&); // friends ::func1<foo<R> > 
}; 
+0

“但你不能在类体中定义专业化”。@Barry如果你看看第一种情况,专业化是使用foo 而不是foo &而且编译失败,因为它在链接时找不到“cout”,但如果使用“printf”,编译成功和朋友专业化被选中。 – xhamr

+0

@xhamr 1)这不是编译失败,这是一个链接器错误2)由于明确的特殊化,代码将无法编译......或者至少会有ODR问题。方式更容易过载。 – Barry

+0

@xhamr对不起,不一定编译失败。请参见[\ [temp.expl.spec \]](http://eel.is/c++draft/temp.expl.spec#6)。 – Barry