Почему я получаю "no match for 'operator ='" для пользовательского класса, если я не перегружаюсь? - PullRequest
0 голосов
/ 08 февраля 2019

Я погуглил и обнаружил такие вопросы, как этот или этот , но, похоже, ни у кого не было той же проблемы, что и у меня.Поиск ошибки (no match for ‘operator=’) и заметки (no known conversion for argument 1) дает мало результатов.

Я создаю анализатор данных, и классы для параметров и выражений нуждаются друг в друге в качестве членов.Я думаю, что правильно реализовал предварительную декларацию, но у меня все еще может быть проблема там.Ниже я приложил все усилия, чтобы минимально воспроизвести ошибку.

parameter.h

#ifndef PARAMETER_H
#define PARAMETER_H


#include <iostream>
#include <string>
#include <vector>

class Expression;

class Parameter {
   public:
    explicit Parameter(std::string&);
    explicit Parameter(Expression*);
    std::string str;
    Expression* e;
    friend std::ostream& operator<<(std::ostream&, const Parameter&);
};

class Expression {
   public:
    Expression(Parameter&, std::string&, Parameter&);
    Parameter l;
    std::string op;
    Parameter r;
    friend std::ostream& operator<<(std::ostream&, const Expression&);
};

#endif  // PARAMETER_H

parameter.cpp

#include "parameter.h"

Parameter::Parameter(std::string& param) : str(param) {}

Parameter::Parameter(Expression* expr) { e = expr; }

std::ostream& operator<<(std::ostream& strm, const Parameter& p) {
    if (p.str.empty()) {
        // parameter is an expression
        strm << *p.e;
    } else {
        // parameter is ID or STRING
        strm << p.str;
    }

    return strm;
}

Expression::Expression(Parameter& left, std::string& oper, Parameter& right) : l(left), op(oper), r(right) {}

std::ostream& operator<<(std::ostream& strm, const Expression& e) {
    strm << "(" << e.l << " " << e.op << " " << e.r << ")";

    return strm;
}

main.cpp

#include <iostream>
#include <string>
#include <vector>

#include "parameter.h"

int main() {
    std::string sample1 = "word";
    std::string sample2 = "another";
    std::string sample3 = "yep";

    std::vector<std::string> samples;
    samples.push_back(sample1);
    samples.push_back(sample2);
    samples.push_back(sample3);

    std::vector<Parameter> params;

    params.insert(params.end(), samples.begin(), samples.end());

    return 0;
}

Я использую gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04).Компиляция с g++ -Wall -Werror -std=c++17 -g *.cpp дает следующее:

In file included from /usr/include/c++/7/bits/char_traits.h:39:0,
             from /usr/include/c++/7/ios:40,
             from /usr/include/c++/7/ostream:38,
             from /usr/include/c++/7/iostream:39,
             from recursiveDescent.h:4,
             from recursiveDescent.cpp:1:
/usr/include/c++/7/bits/stl_algobase.h: In instantiation of ‘static _OI 
std::__copy_move<false, false, 
std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = 
std::__cxx11::basic_string<char>*; _OI = Parameter*]’:
/usr/include/c++/7/bits/stl_algobase.h:386:44:   required from 
[...skipped...] required from here
/usr/include/c++/7/bits/stl_algobase.h:324:18: error: no match for ‘operator=’ (operand types are ‘Parameter’ and ‘std::__cxx11::basic_string<char>’)
    *__result = *__first;
    ~~~~~~~~~~^~~~~~~~~~
In file included from predicate.h:8:0,
                 from datalogProgram.h:8,
                 from recursiveDescent.h:8,
                 from recursiveDescent.cpp:1:
parameter.h:10:7: note: candidate: Parameter& Parameter::operator=(const Parameter&)
 class Parameter {
   ^~~~~~~~~
parameter.h:10:7: note:   no known conversion for argument 1 from ‘std::__cxx11::basic_string<char>’ to ‘const Parameter&’
parameter.h:10:7: note: candidate: Parameter& Parameter::operator=(Parameter&&)
parameter.h:10:7: note:   no known conversion for argument 1 from ‘std::__cxx11::basic_string<char>’ to ‘Parameter&&’

1 Ответ

0 голосов
/ 08 февраля 2019

Конструктор OP Parameter::Parameter(std::string&) (или, как указал PeterT, лучше Parameter::Parameter(const std::string&)) может (и будет) использоваться для неявного преобразования std::string в Parameter в

params.insert(params.end(), samples.begin(), samples.end());

, ноOP явно запретил это, сделав его explicit.

. Я часто использую explicit для конструкторов, которые можно вызывать с одним аргументом, потому что я боюсь случайных преобразований (и мне бы хотелось, чтобы иллюзияимея контроль над моим кодом).В этом случае может быть проще отбросить explicit.

Образец:

#include <iostream>
#include <string>
#include <vector>

class Parameter {
  private:
    std::string _name;
  public:
    /*explicit*/ Parameter(const std::string &name): _name(name) { }
    const std::string& name() const { return _name; }
};

std::ostream& operator<<(std::ostream &out, const Parameter &param)
{
  return out << "Parameter '" << param.name() << "'";
}

template <typename T>
std::ostream& operator<<(std::ostream &out, const std::vector<T> &vec)
{
  const char *sep = "";
  for (const T &elem : vec) {
    out << sep << elem;
    sep = ", ";
  }
  return out;
}

int main()
{
  const std::vector<std::string> samples({ "word", "another", "yep" });
  std::vector<Parameter> params;
  params.insert(params.end(), samples.begin(), samples.end());
  std::cout << "params: " << params << '\n';
  return 0;
}

Выход:

params: Parameter 'word', Parameter 'another', Parameter 'yep'

Live демо на coliru

...