“对于'操作符的”不确定的过载“ *没有*全部超载 [英] "ambiguous overload for 'operator<<'" *without* a catch-all overload

查看:738
本文介绍了“对于'操作符的”不确定的过载“ *没有*全部超载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我尝试将 xorshift PRNG作为参数化的STL样式类从 random ,例如 std :: mersenne_twister_engine ,所以我可以使用它从那些非常方便的分发从随机库等。 >

无论如何,我有一个重载运算符<< 的问题,坦白说,我完全 > stumped。



类的参数化如下:

  < size_t __n,
int_least8_t __a,int_least8_t __b,int_least8_t __c,
uint64_t __m>
class xorshift_engine
{
...

在类中这样声明为朋友

  size_t __n_,
int_least8_t __a_,int_least8_t __b_,int_least8_t __c_,
uint64_t __m_,
typename _CharT,typename _Traits>
friend std :: basic_istream< _CharT,_Traits>&
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
const xorshift_engine< __ n_,__a_,__b_,__c_,__m_>& _x)

并且类外部的实现类似如下:

 模板 int_least8_t __a,int_least8_t __b,int_least8_t __c,
uint64_t __m,
typename _CharT,typename _Traits>
std :: basic_ostream< _CharT,_Traits>&
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
const xorshift_engine< __ n,__a,__b,__c,__m>& _x)
{
...
}

当我尝试编译以下内容时:

  #include< iostream> 
#include< random>
#includexorshift.hpp

using namespace std;

int main()
{
xorshift1024star bip(2345);
mt19937_64 bip2(2345);
cout<< bip<< endl;
cout<< endl<< bip2< endl;
return 0;
}

xorshift1024star 只是实例化 xorshift_engine 类:

  typedef xorshift_engine < -31,11,30,1181783497276652981ULL> xorshift1024star; 

)我收到此错误在 --- 的文件路径中):

  C: \\Users\ --- \Documents\randgen.cpp:在函数'int main()':
C:\Users\ --- \Documents\randgen.cpp:11: 7:error:'operator<<'(操作数类型为'std :: ostream {aka std :: basic_ostream< char>}'和'xorshift1024star {aka xorshift_engine< 16ull,-31,11,30,1181783497276652981ull> ;}')
cout<< bip<< endl;
^
C:\Users \ --- \Documents \randgen.cpp:11:7:注意:候选项是:
在包含在C:\Users \ --- \Documents\randgen.cpp:3:0:
C:\Users\ --- \Documents\xorshift.hpp:898:1:note:std :: basic_ostream< _CharT,_Traits>&运算符<<<<(std :: basic_ostream< _CharT,_Traits>& const xorshift_engine< __ n,__a,__b,__c,__m& signed char __a = -31; signed char __b = 11; signed char __c = 30; long long unsigned int __m = 1181783497276652981ull; _CharT = char; _Traits = std :: char_traits< char>]
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
^
C:\Users\ --- \Documents\xorshift.hpp:858:2:note:std: :basic_istream< _CharT,_Traits>& operator<<(std :: basic_ostream< _CharT,_Traits>& const xorshift_engine< __ n_,__a_,__b_,__c_,__m_& 16ull; signed char __a_ = -31; signed char __b_ = 11; signed char __c_ = 30; long long unsigned int __m_ = 1181783497276652981ull; _CharT = char; _Traits = std :: char_traits< char> long long unsigned int __n = 16ull ; signed char __a = -31; signed char __b = 11; signed char __c = 30; long long unsigned int __m = 1181783497276652981ull]
operator<<(std :: basic_ostream< _CharT,_Traits&
^
来自C:/mingw-w64/x86_64-4.9.0-posix-seh-rt_v3-rev1/mingw64/x86_64-w64-mingw32/include/c ++ / iostream:39: 0,
来自C:\Users\ --- \Documents\randgen.cpp:1:
C:/mingw-w64/x86_64-4.9.0-posix-seh-rt_v3 -rev1 / mingw64 / x86_64-w64-mingw32 / include / c ++ / ostream:602:5:note:std :: basic_ostream< _CharT,_Traits& std :: operator<<<(std :: basic_ostream< _CharT,_Traits>&&&& const _Tp&)[with _CharT = char; _Traits = std :: char_traits< char> ;; _Tp = xorshift_engine< 16ull,-31,11,30,1181783497276652981ull>]< near match>
operator<<(basic_ostream< _CharT,_Traits>&& __os,const _Tp& __x)
^
C:/mingw-w64/x86_64-4.9.0-posix- seh-rt_v3-rev1 / mingw64 / x86_64-w64-mingw32 / include / c ++ / ostream:602:5:注意:从'std :: ostream {aka std :: basic_ostream< char>}' 'std :: basic_ostream< char>&&'

bits / random.h 中的 mersenne_twister_engine 中声明:

  template< typename _UIntType1,
size_t __w1,size_t __n1,
size_t __m1,size_t __r1,
_UIntType1 __a1,size_t __u1,
_UIntType1 __d1,size_t __s1,
_UIntType1 __b1,size_t __t1,
_UIntType1 __c1,size_t __l1,_UIntType1 __f1,
typename _CharT,typename _Traits>
friend std :: basic_ostream< _CharT,_Traits>&
operator<<<(std :: basic_ostream< _CharT,_Traits>& __os,
const std :: mersenne_twister_engine< _UIntType1,__w1,__n1,
__m1,__r1,__a1,__u1, __d1,__s1,__b1,__t1,__c1,
__l1,__f1>& __x);

并在 bits / random.tcc

  template< typename _UIntType,size_t __w,
size_t __n,size_t __m,size_t __r,
_UIntType __a,size_t __u,_UIntType __d,size_t __s,
_UIntType __b,size_t __t,_UIntType __c,size_t __l,
_UIntType __f,typename _CharT,typename _Traits>
std :: basic_ostream< _CharT,_Traits>&
operator<<<<(std :: basic_ostream< _CharT,_Traits>& __os,
const mersenne_twister_engine< _UIntType,__w,__n,__m,
__r,__a,__u,__d,__s ,__b,__t,__c,__l,__f>& __x)
{
...
}

如果我注释掉了 cout<< bip<< endl; 在我的测试代码中,它编译并运行没有错误,所以这个重载是好的,但我的不是。



完全脱离了想法。我缺少什么?






编辑:对于那些建议它是模板朋友的问题,我应该解决通过转发声明函数,我刚刚添加

  template< size_t __n,
int_least8_t __a,int_least8_t __b,int_least8_t __c,
uint64_t __m>
class xorshift_engine;

template< size_t __n,
int_least8_t __a,int_least8_t __b,int_least8_t __c,
uint64_t __m,
typename _CharT,typename _Traits>
std :: basic_ostream< _CharT,_Traits>&
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
const xorshift_engine< __ n,__a,__b,__c,__m>& _x)

之前,我在尝试编译时遇到同样的错误。






edit2:提供相同编译错误的简化示例:

  //文件failclass.hpp

#ifndef _FAILCLASS_HPP
#define _FAILCLASS_HPP

#include < iosfwd>
#include< type_traits>

template< int n>
class failclass
{
private:
static constexpr int k = n;

public:
template< int n1,typename _CharT,typename _Traits>
friend std :: basic_istream< _CharT,_Traits>&
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
const failclass< n1>& _x);
};

template< int n1,typename _CharT,typename _Traits>
std :: basic_ostream< _CharT,_Traits>&
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
const failclass< n1>& _x)
{
_os& _x.k;
return _os;
}

#endif // _FAILCLASS_HPP

尝试编译这:

  // filefailtest.cpp

#include< iostream>
#includefailclass.hpp

using namespace std;

int main()
{
failclass< 5>一个;
cout<<一个;
return 0;
}


解决方案

下面为它的值,但是特定的错误只是一个拼写错误:

  template< size_t __n_,
int_least8_t __a_ ,int_least8_t __b_,int_least8_t __c_,
uint64_t __m_,
typename _CharT,typename _Traits>
friend std :: basic_istream< _CharT,_Traits>&
// ^ - 你可能意味着std :: ostream !!!!!
operator<< (std :: basic_ostream< _CharT,_Traits>& _os,
const xorshift_engine< __ n_,__a_,__b_,__c_,__m_>& _x)

在命名空间级别定义的模板和朋友采用完全相同的参数,但返回类型不同。






以下大部分内容并不能直接解决您的错误讯息,它。我个人认为,前瞻性声明应该固定。如果没有,您应该提供一个SCCE。



为了讨论,让我们简化一个代码到一个模板,以实现运算符<< 。朋友声明:

 模板< typename T& 
class Tmpl {
friend std :: ostream& operator<<(std :: ostream& amp; Tmpl const&);
};

提供非模板独立函数的声明运算符<<< / code>获取 std :: ostream& Tmpl& const& 。这里有一个重要的细节,这不是一个模板,或任何自由功能的朋友。给定特殊化 Tmpl ,该声明在同一命名空间中结合具有以下签名的函数:

  std :: ostream&运算符<<<(std :: ostream& out,Tmpl< int> const& obj){
// I can access Tmpl&内部!
return out;
}

虽然这是一种可能的方法,可能不想为模板的每个专业化提供不同的免费功能。



此时,有一个非常有趣的朋友声明:你可以在类中提供定义,以及朋友声明:

 模板< typename T> 
class Tmpl {
friend std :: ostream&运算符<<<(std :: ostream out,Tmpl const& t){
// definition here
return out;
}
};

这里有趣的是,对于 Tmpl ,编译器会为你生成一个非模板自由函数,可以访问类型的内部。



现在,在这种特殊情况下可能需要考虑其他替代方案。第一个想到的,我经常使用它,不是让操作符< <朋友,而是提供 code>函数(你可以添加其他参数到控制输出),然后通过调用<$ c来实现运算符<< $ c> print 。您可以选择仍然使运算符<< 一个在 [1] 类中定义的朋友,或者您可以提供一个模板< c $ c>::<$ p> $ <$ p> $ <$ p> $ <$ c>

template< typename T>
class Tmpl {
public:
std :: ostream& print(std :: ostream& out)const;
//选项1:
friend std :: ostream& operator<<<(std :: ostream& out,Tmpl const& obj){
return obj.print(out);
}
};
//选项2:
模板< typename T>
std :: ostream&运算符<<<(std :: ostream& out,Tmpl< T> const& obj){
return obj.print
}

另一个不同的选择(我不推荐,为了完整性)将上面的模板声明为朋友:

  template< typename T& 
class Tmpl {
public:
template< typename U>
friend std :: ostream&运算符<<(std :: ostream& out,Tmpl U const& obj);
};
//模板定义为上面的选项2

但这是一个 / strong>想法(以及您选择的替代品),运算符<< < int> 可以访问 Tmpl ,并且很容易破坏封装。



一个稍微好一些的选择是只需要 上面的模板的精确匹配的参数,但这是一个更复杂的代码:

 模板< typename T>类别Tmpl; 
template< typename T>
std :: ostream&运算符<<(std :: ostream& amp; Tmpl< T> const&
template< typename T>
class Tmpl {
friend std :: ostream&运算符<< < T>(std :: ostream& amp; Tmpl T const&);
};






1 仍然使运营商朋友的原因,即使它仅仅根据公共接口来实现,它隐藏了运营商从正常的 查找,并使其仅可用于ADL。


So I am trying to implement the xorshift PRNGs as a parameterised STL-style class from random, like e.g. std::mersenne_twister_engine, so I can use it with those quite convenient distributions from the random library etc.

Anyway, I have a problem overloading the operator<< and, frankly, I am completely stumped.

The class is parameterised like this:

template <size_t __n,
          int_least8_t __a, int_least8_t __b, int_least8_t __c,
          uint64_t __m>
class xorshift_engine
{
...

The overload is declared as a friend inside the class like this:

template <size_t __n_,
          int_least8_t __a_, int_least8_t __b_, int_least8_t __c_,
          uint64_t __m_,
          typename _CharT, typename _Traits>
friend std::basic_istream<_CharT, _Traits>&
operator<< (std::basic_ostream<_CharT, _Traits>& _os,
            const xorshift_engine<__n_, __a_, __b_, __c_, __m_>& _x);

and its implementation outside the class looks like this:

template <size_t __n,
          int_least8_t __a, int_least8_t __b, int_least8_t __c,
          uint64_t __m,
          typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>&
operator<< (std::basic_ostream<_CharT, _Traits>& _os,
            const xorshift_engine<__n, __a, __b, __c, __m>& _x)
{
    ...
}

When I try to compile the following:

#include <iostream>
#include <random>
#include "xorshift.hpp"

using namespace std;

int main()
{
    xorshift1024star bip(2345);
    mt19937_64 bip2(2345);
    cout << bip << endl;
    cout << endl << bip2 << endl;
    return 0;
}

(xorshift1024star is just an instantiation of the xorshift_engine class:

typedef xorshift_engine<16, -31, 11, 30, 1181783497276652981ULL> xorshift1024star;

) I get this error (I replaced my username in the file paths with ---):

C:\Users\---\Documents\randgen.cpp: In function 'int main()':
C:\Users\---\Documents\randgen.cpp:11:7: error: ambiguous overload for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'xorshift1024star {aka xorshift_engine<16ull, -31, 11, 30, 1181783497276652981ull>}')
  cout << bip << endl;
       ^
C:\Users\---\Documents\randgen.cpp:11:7: note: candidates are:
In file included from C:\Users\---\Documents\randgen.cpp:3:0:
C:\Users\---\Documents\xorshift.hpp:898:1: note: std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>&, const xorshift_engine<__n, __a, __b, __c, __m>&) [with long long unsigned int __n = 16ull; signed char __a = -31; signed char __b = 11; signed char __c = 30; long long unsigned int __m = 1181783497276652981ull; _CharT = char; _Traits = std::char_traits<char>]
 operator<< (std::basic_ostream<_CharT, _Traits>& _os,
 ^
C:\Users\---\Documents\xorshift.hpp:858:2: note: std::basic_istream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>&, const xorshift_engine<__n_, __a_, __b_, __c_, __m_>&) [with long long unsigned int __n_ = 16ull; signed char __a_ = -31; signed char __b_ = 11; signed char __c_ = 30; long long unsigned int __m_ = 1181783497276652981ull; _CharT = char; _Traits = std::char_traits<char>; long long unsigned int __n = 16ull; signed char __a = -31; signed char __b = 11; signed char __c = 30; long long unsigned int __m = 1181783497276652981ull]
  operator<< (std::basic_ostream<_CharT, _Traits>& os,
  ^
In file included from C:/mingw-w64/x86_64-4.9.0-posix-seh-rt_v3-rev1/mingw64/x86_64-w64-mingw32/include/c++/iostream:39:0,
                 from C:\Users\---\Documents\randgen.cpp:1:
C:/mingw-w64/x86_64-4.9.0-posix-seh-rt_v3-rev1/mingw64/x86_64-w64-mingw32/include/c++/ostream:602:5: note: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = xorshift_engine<16ull, -31, 11, 30, 1181783497276652981ull>] <near match>
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^
C:/mingw-w64/x86_64-4.9.0-posix-seh-rt_v3-rev1/mingw64/x86_64-w64-mingw32/include/c++/ostream:602:5: note:   no known conversion for argument 1 from 'std::ostream {aka std::basic_ostream<char>}' to 'std::basic_ostream<char>&&'

For reference, this is how the overload is declared inside mersenne_twister_engine in bits/random.h:

template<typename _UIntType1,
         size_t __w1, size_t __n1,
         size_t __m1, size_t __r1,
         _UIntType1 __a1, size_t __u1,
         _UIntType1 __d1, size_t __s1,
         _UIntType1 __b1, size_t __t1,
         _UIntType1 __c1, size_t __l1, _UIntType1 __f1,
         typename _CharT, typename _Traits>
friend std::basic_ostream<_CharT, _Traits>&
operator<<(std::basic_ostream<_CharT, _Traits>& __os,
           const std::mersenne_twister_engine<_UIntType1, __w1, __n1,
           __m1, __r1, __a1, __u1, __d1, __s1, __b1, __t1, __c1,
           __l1, __f1>& __x);

and its implementation in bits/random.tcc:

template<typename _UIntType, size_t __w,
         size_t __n, size_t __m, size_t __r,
         _UIntType __a, size_t __u, _UIntType __d, size_t __s,
         _UIntType __b, size_t __t, _UIntType __c, size_t __l,
         _UIntType __f, typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>&
operator<<(std::basic_ostream<_CharT, _Traits>& __os,
           const mersenne_twister_engine<_UIntType, __w, __n, __m,
           __r, __a, __u, __d, __s, __b, __t, __c, __l, __f>& __x)
{
  ...
}

If I comment out the cout << bip << endl; line in my test code, it compiles and runs without error, so this overload is fine, but mine is not.

I am completely out of ideas. What am I missing? I would be more than grateful if someone could help me.


edit: For those suggesting it's the "template friends" problem which I should solve by forward-declaring the function, I have just added

template <size_t __n,
          int_least8_t __a, int_least8_t __b, int_least8_t __c,
          uint64_t __m>
class xorshift_engine;

template <size_t __n,
          int_least8_t __a, int_least8_t __b, int_least8_t __c,
          uint64_t __m,
          typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>&
operator<< (std::basic_ostream<_CharT, _Traits>& _os,
            const xorshift_engine<__n, __a, __b, __c, __m>& _x);

before the class body/implementation, and I get the same error upon attempting to compile.


edit2: Simplified example giving the same compile error:

//file "failclass.hpp"

#ifndef _FAILCLASS_HPP
#define _FAILCLASS_HPP

#include <iosfwd>
#include <type_traits>

template <int n>
class failclass
{
private:
    static constexpr int k = n;

public:
    template<int n1, typename _CharT, typename _Traits>
    friend std::basic_istream<_CharT, _Traits>&
    operator<< (std::basic_ostream<_CharT, _Traits>& _os,
                const failclass<n1>& _x);
};

template<int n1, typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>&
operator<< (std::basic_ostream<_CharT, _Traits>& _os,
            const failclass<n1>& _x)
{
    _os << _x.k;
    return _os;
}

#endif // _FAILCLASS_HPP

Try to compile this:

//file "failtest.cpp"

#include <iostream>
#include "failclass.hpp"

using namespace std;

int main()
{
    failclass<5> a;
    cout << a;
    return 0;
}

解决方案

Leaving the rest of the answer below for its value, but the particular error is just a typo:

template <size_t __n_,
              int_least8_t __a_, int_least8_t __b_, int_least8_t __c_,
              uint64_t __m_,
              typename _CharT, typename _Traits>
    friend std::basic_istream<_CharT, _Traits>&
//                    ^     -- you probably meant std::ostream!!!!!
    operator<< (std::basic_ostream<_CharT, _Traits>& _os,
                const xorshift_engine<__n_, __a_, __b_, __c_, __m_>& _x);

The template defined at namespace level and the friend take exactly the same arguments, but have a different return type.


Most of the following is not a direct answer to your error message, but tackles the root problem that got you into it. Personally I believe that the forward declaration should have fixed it. If it doesn't, you should provide a SCCE.

For the sake of discussion, lets simplify a bit the code to a template with a single argument for which you want to implement operator<<. The friend declaration:

template <typename T>
class Tmpl {
    friend std::ostream& operator<<(std::ostream&, Tmpl const &);
};

Provides a declaration for a non-template standalone function operator<< taking a std::ostream& and a Tmpl<T> const &. There is an important detail here, this is not befriending a template, or any free function. Given a specialization Tmpl<int>, the declaration befriends a function in the same namespace with the following signature:

std::ostream& operator<<(std::ostream& out, Tmpl<int> const & obj) {
   // I can access Tmpl<int> internals!
   return out;
}

While this is a possible approach, you most probably don't want to have to manually provide a different free function for each specialization of your template.

At this point there is a really interesting feature of a friend declaration: you can provide the definition inside the class, together with the friend declaration:

template <typename T>
class Tmpl {
    friend std::ostream& operator<<(std::ostream out, Tmpl const & t) {
       // definition goes here
       return out;
    }
};

The interesting point here is that, for each specialization of Tmpl, the compiler will generate for you a non-template free function that has access to the internals of the type.

Now, in this particular case, you might want to consider other alternatives. The first that comes to mind, as I often use it, is not to make operator<< a friend, but to provide a print function (to which you can add other arguments to control output), and then implement operator<< in terms of the public interface by calling print. You can opt to still make operator<< a friend that is defined inside the class [1], or you can provide a templated operator<< that calls print:

template <typename T>
class Tmpl {
public:
   std::ostream& print(std::ostream& out) const;
   // option 1:
   friend std::ostream& operator<<(std::ostream& out, Tmpl const & obj) {
       return obj.print(out);
   }
};
// option 2:
template <typename T>
std::ostream& operator<<(std::ostream& out, Tmpl<T> const & obj) {
   return obj.print(out);
}

A different alternative (which I don't recommend, but well, for the sake of completeness) is to declare the template above a friend:

template <typename T>
class Tmpl {
public:
   template <typename U>
   friend std::ostream& operator<<(std::ostream& out, Tmpl<U> const & obj);
};
// template defined as option 2 above

But this is a bad idea (and the alternative you opted for), as operator<< <int> will have access to Tmpl<double>, and it is quite easy to break encapsulation.

A slightly better alternative is to befriend only the specialization of the above template that exactly matches the arguments, but this is a bit more convoluted in code:

template <typename T> class Tmpl;
template <typename T>
std::ostream& operator<<(std::ostream&, Tmpl<T> const &);
template <typename T>
class Tmpl {
    friend std::ostream& operator<< <T>(std::ostream&, Tmpl<T> const &);
};


1 The possible reason to still make operator<< a friend even if it is implemented only in terms of the public interface is that it hides the operator from normal lookup, and makes it available only for ADL.

这篇关于“对于'操作符的”不确定的过载“ *没有*全部超载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆