简体   繁体   English

模板结构中的Friend运算符会引发重定义错误

[英]Friend operator in template struct raises redefinition error

Consider this code: 考虑以下代码:

template<typename T,typename K>
struct A{

   friend std::ostream& operator<<(std::ostream& out, K x) { 
      // Do some output 
      return out; 
   }

};

int main(){
   A<int,int> i;
   A<double,int> j;
}

It does not compile, because the two instantiations of A instantiate the operator<< two times with the same signature, so I receive this error: 它不编译,因为A的两个实例化实例化operator<<两次具有相同的签名,所以我收到此错误:

test.cpp:26:25: error: redefinition of ‘std::ostream& operator<<(std::ostream&, int)’
    friend std::ostream& operator<<(std::ostream& out, K x) { return out; }
                         ^
test.cpp:26:25: error: ‘std::ostream& operator<<(std::ostream&, int)’ previously defined here

How to fix this? 如何解决这个问题? How can I have a friend operator in a template, when that operator might have the same signature for two different instantiations? 如果该运算符可能具有两个不同实例的相同签名,那么如何在模板中拥有友元运算符? How can I solve this without triggering a redefinition error? 如何在不触发重新定义错误的情况下解决此问题?

I don't really see any use in declaring a friend like this, nevertheless this is how you can do it: 我觉得在宣布这样的朋友时没有任何用处,不过这就是你如何做到的:

template<typename T, typename K>
struct A{
  template<typename L>
  friend std::ostream& operator<<(std::ostream& out, L const &x);
};

template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x) {
  // ... 
  return out;
}

LIVE DEMO 现场演示

Edit: 编辑:

Another option probably closer to what you want will be: 另一种选择可能更接近你想要的是:

template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x);

template<typename T, typename K>
struct A{
  friend std::ostream& operator<<<K>(std::ostream& out, K const &x);
};

template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x) { 
  // ...
  return out;
}

LIVE DEMO 现场演示

But really not sure why you want this. 但是真的不确定你为什么要这样。 IMHO your design has serious flaws. 恕我直言,你的设计有严重的缺陷。

Your question is faulty in the following way. 您的问题以下列方式出错。

Assuming it's a stub and your class has something private such that it needs to declare a friend, the purpose of doing so is that the friend is external to the class itself but has access to what is private within it. 假设它是一个存根,你的类有一些私有的东西,它需要声明一个朋友,这样做的目的是朋友是类本身的外部,但可以访问其中的私有。

In your case you are declaring streaming functions of a parameter as a friend. 在您的情况下,您将参数的流功能声明为朋友。 That is fine. 那也行。 It means if someone creates a class Bar and wants to define how a Bar is streamed their implementation may access anything in A<T,Bar> for any type T . 这意味着如果有人创建了一个类Bar并且想要定义一个Bar如何流式传输,那么它们的实现可以访问任何类型T A<T,Bar>中的任何内容。

The clashing of your template with operator<<( ostream&, int) is not actually a problem as the compiler knows which one to pick. 模板与operator<<( ostream&, int)的冲突实际上并不是问题,因为编译器知道要选择哪一个。 It will always pick the exact match non-templated over the templated one. 它总是会选择非模板化的精确匹配。 Your problem is that you have 2 templated ones and the compiler cannot pick between them because they are both equally valid. 你的问题是你有两个模板化的,编译器不能在它们之间进行选择,因为它们都是同等有效的。

Maybe something like this is what you are really trying to achieve 也许这样的事情是你真正想要实现的目标

template< typename X, typename Y >
struct A
{
   friend void a_print( std::ostream& Y const & ); // foo external function with Y as parameter, can access this
};

std::ostream & operator<<( std::ostream & out, Bar const& bar )
{
   a_print( out, bar );
   return out;
}

void a_print( Bar const& bar, std::ostream & out )
{
   // implement and call private members of A<Foo, Bar>
   return out;
}

You could make the streaming template a friend and implement the one for Bar to stream using a specific implementation. 您可以将流模板设为朋友,并使用特定实现实现Bar的流式传输。

Factor the method out to a base class: 将方法分解为基类:

template <typename K>
struct ABase
{
   friend std::ostream& operator<<(std::ostream& out, K x) { 
      // Do some output 
      return out; 
   }
};

template <typename T,typename K>
struct A : public ABase<K>
{};

If you want to stream an A object, the proper signature should have been 如果要流式传输A对象,则应该使用正确的签名

template<typename T,typename K>
struct A{

   friend std::ostream& operator<<(std::ostream& out, const A& x) { 
      // Do some output 
      return out; 
   }

};

taking an A<T,K> for which you can access private members, not a K . A<T,K>你可以访问私人会员,而不是K

If there is no way to get an A from K (and cannot be if K is int ), making <<(ostream&,K) a friend of A gives no benefits. 如果没有办法从K获得A(并且如果Kint则不能),使<<(ostream&,K)成为A的朋友没有任何好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM