繁体   English   中英

如何在C ++中强制不使用转换构造函数

[英]How to force not to use conversion constructor in C++

我正在研究一个带矩阵的项目,我遇到了重载运算符的问题。

我已经声明了这些用户友好的输入/输出功能:

friend std::istream& operator>>(std::istream& is, MathMatrix& m); //keyboard input
friend std::ostream& operator<<(std::ostream& os, const MathMatrix& m); // screen output
friend std::ifstream& operator>>(std::ifstream& ifs, MathMatrix& m); // file input
friend std::ofstream& operator<<(std::ofstream& ofs, const MathMatrix& m); // file output

在定义它们中的最后一个时,在这段简单的代码中,我遇到了一个错误,无法编译:

// file output
std::ofstream& operator<<(std::ofstream& ofs, const MathMatrix& m) {
    //put matrix dimension in first line
    ofs << m.n << std::endl;
    //put data in third line
    for (int i=0; i<m.n; i++) {
        for (int j=0; j<m.n; j++) ofs << m(i,j) << " ";
        ofs << std::endl;
    }
    return ofs;
}

错误在ofs << mn (和ofs << m(i,j)的类似)。 它说:

const MathMatrix &m
Error: more than one operator "<<" matches these operands:
    function "operator<<(std::ofstream &ofs, const MathMatrix &m)"
    function "std::basic_ostream<_Elem, _Traits>::operator<<(int _Val) [with _Elem=char, _Traits=std::char_traits<char>]"
    operand types are std::ofstream << const int

过了一会儿我觉得问题可能就是我有一个像MathMatrix (int n)这样的MathMatrix构造函数,因此编译器可能会尝试从int n转换为MathMatrix(int n) 我不明白为什么它会这样做,但这是我能想到的唯一解释,给出IDE给出的解释。

你能看到我错过的东西吗? 你知道怎么解决吗?

如果在您的类中有一个构造函数,其单个参数的类型与您的类不同,则可以将其用于隐式类型转换。 为了防止您只需要将该构造函数标记为显式:

class MathMatrix {
public:
   explicit MathMatrix( int m );
...
};

始终将单个参数构造函数标记为显式是个好主意(除非参数是相同的类类型,或者您确实需要这样的类型转换)

重载决策中存在一个微妙之处,导致在调用ofs << mn的函数时选择函数之间存在模糊性。 这是一个重现问题的简短示例:

struct Base
{
    void operator<<(int);
};

struct Derived : Base
{
};

struct converter
{
    converter(int);
};

void operator<<(Derived&, converter const&);

int main()
{
    const int i = 42;
    Derived d;
    d << i;
}

为什么电话不明确?

首先,成员函数Base::operator<<获取Base&类型的附加参数,仅用于重载解析[over.match.funcs] / 2

候选函数集可以包含要针对同一参数列表解析的成员函数和非成员函数。 因此,参数列表和参数列表在此异构集中是可比较的,成员函数被认为具有额外的参数,称为隐式对象参数 ,其表示已调用成员函数的对象。

由于成员函数(甚至在Derived继承)是Base的成员函数,因此参数类型是Base& ,而不是Derived ; 见/ 4。

因此我们比较

void operator<<(Base&, int);                  // #0
void operator<<(Derived&, converter const&);  // #1

调用d << i的参数是Derived (左值)和const int 因此:

  1. 过载#0
    1. 对于第一个参数,需要派生到基础的转换
    2. 对于第二个参数,需要进行限定转换( const int to int
  2. 过载#1
    1. 对于第一个参数,完全匹配(无转换)
    2. 对于第二个参数,需要进行限定转换,然后进行用户定义的转换( const int to intint to converter

转换1.1比转换2.1差,但转换1.2优于转换2.2。 因此,呼叫是模糊的。


如何解决歧义?

或者:

  • (首选)使MathMatrix的转换显式化
  • 只声明一个operator<<(std::ostream&, MathMatrix const&) ,但没有std::ofstream (这将使1.1等于1.2,因此重载#1成为更好的匹配)
  • 将调用中的std::ofstream显式转换为基类std::ostream (有助于以前的版本)
  • 隐藏有问题的重载,例如通过using std::operator<<;using声明 using std::operator<<;

暂无
暂无

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

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