Foo f = Foo ();//никакое соответствие функционируют для вызова 'Foo:: Foo (Нечто)' … ха?

class Foo
{
public:
    explicit Foo() {}
    explicit Foo(Foo&) {}
};

Foo d = Foo();

ошибка: никакая функция соответствия для вызова к 'Нечто:: Нечто (Нечто)'

Я пытался измениться Foo(Foo&) кому: Foo(Foo) как ошибка предполагает, какой AFAIK не является допустимым конструктором, и конечно же я добираюсь:

ошибка: недопустимый конструктор; Вы, вероятно, имели в виду ‘Нечто (константа Foo&)’

Что дает? Как я разрешаю это? (Это находится на GCC между прочим),

12
задан Bill the Lizard 5 May 2010 в 19:56
поделиться

10 ответов

В вашем конструкторе копирования есть две сомнительные вещи.

Во-первых, вы сделали конструктор копирования явным (что сомнительно), поэтому (теоретически) вам нужно сделать:

Foo d( (Foo()) );

Во-вторых, ваш конструктор копирования принимает ссылку, а не const, что означает, что вы не можете использовать его с временным Foo.

Лично я бы просто убрал explicit из конструктора копирования и заставил бы его принимать const ссылку, если это возможно.

Обратите внимание, что explicit в конструкторе по умолчанию не имеет никакого эффекта. [*] explicit имеет эффект только на конструкторы, которые могут быть вызваны с одним параметром. Это предотвращает их использование для неявных преобразований. Для конструкторов, принимающих только ноль или только два или более параметров, он не имеет эффекта.

[Примечание: может быть разница между:

Foo d;

и

Foo d = Foo();

но в данном случае у вас есть объявленный пользователем конструктор по умолчанию, так что это не применимо.]

Редактировать: [*] Я только что дважды проверил это, и в 12.3.1 [class.conv.ctor] говорится, что вы можете сделать конструктор по умолчанию явным. В этом случае конструктор будет использоваться для выполнения инициализации по умолчанию или инициализации по значению. Честно говоря, я не понимаю значения этого, поскольку если у вас есть объявленный пользователем конструктор, то это не-POD тип, и даже локальные объекты не-POD типа инициализируются по умолчанию, если у них нет инициализатора, который, согласно этому пункту, может быть выполнен явным конструктором по умолчанию. Возможно, кто-то сможет указать на угловой случай, когда это имеет значение, но пока я не вижу, какое влияние explicit имеет на конструктор по умолчанию.

13
ответ дан 2 December 2019 в 04:42
поделиться

Вы не хотите отмечать ни один из этих конструкторов как явный - компилятор должен использовать их оба, особенно конструктор копирования, неявно. Чего вы пытаетесь достичь, помечая их явным образом?

5
ответ дан 2 December 2019 в 04:42
поделиться

Компилятор сообщает вам ... Используйте это:

Foo(const Foo&) {}
1
ответ дан 2 December 2019 в 04:42
поделиться

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

Во-вторых, убедитесь, что конструктор копирования принимает ссылку const .

В-третьих, Foo f; - это правильный способ создать объект класса foo, созданный по умолчанию. Обратите внимание, что Foo f (); неверно, потому что компилятор интерпретирует это как объявление функции f () , которая возвращает объект класса Foo .

В-четвертых, если вы написали свой собственный конструктор копирования, вам также следует написать оператор присваивания.


class Foo
{
  Foo() {} // no need to make explicit.  Nothing to convert from.

  Foo(const &Foo f) {} // again, nothing wrong with conversion from Foo to Foo

  explicit Foo(int a) {}  // need explicit to prevent accidental passing of an int
                          // to a function that takes Foo as an argument
};

4
ответ дан 2 December 2019 в 04:42
поделиться

Конструктор копирования не должен быть явным (что делает его uncallable здесь и во многих других вполне разумных контекстах, например, при передаче или возврате по значению).

Затем он должен принять аргумент по ссылке const , поскольку в противном случае он не может привязаться к временным файлам.

Foo f = Foo();
        ^^^^^
          |
          --- this is a temporary that cannot be passed to a function
              that accepts a non-const reference

Кроме того, нет причин делать конструктор по умолчанию явным : это ключевое слово имеет смысл только для конструкторов (кроме конструктора копирования), которые могут быть вызваны ровно с одним аргументом, и в этом случае оно предотвращает неявные преобразования других типов в Foo через этот конструктор. Например, если конструктор, принимающий int , был явным , такие ситуации не будут компилироваться:

Foo f;
f = 1;  //assuming no operator= overload for (types convertible from) int
        //this implicitly performs f = Foo(1);

Foo g = 10;

void x(Foo);
x(20);

В целом:

class Foo
{
public:
    Foo();
    Foo(const Foo&);
    //...
};

Foo x = Foo();

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

3
ответ дан 2 December 2019 в 04:42
поделиться
class Foo
{
public:
    explicit Foo() {}
    explicit Foo(const Foo&) {}
};

Foo d = Foo()
-1
ответ дан 2 December 2019 в 04:42
поделиться
Foo d = Foo();

должно быть

Foo d;

Первая строка создает экземпляр Foo, а затем копирует его в d;

2
ответ дан 2 December 2019 в 04:42
поделиться

Попробуйте без явного? Я думаю, что:

Foo foo = Foo()

создает неявную копию, поэтому явный конструктор копирования не срабатывает.

Edit:

Это только половина ответа. Смотрите пост Чарльза Бейли или UncleBens о том, зачем нужна const.

3
ответ дан 2 December 2019 в 04:42
поделиться

Ваша проблема в инстанцировании. Вам не нужно Foo d = Foo(); для конструктора по умолчанию.

Оставьте свой класс прежним, но попробуйте сделать вот так:

Foo d;

На самом деле, вам даже не нужно Foo d = Foo(arguments); для конструирования с параметрами. Это должно выглядеть так:

Foo d(arguments);
2
ответ дан 2 December 2019 в 04:42
поделиться

Вы можете решить эту проблему одним из двух способов. Первый (уже предложенный Randolpho) - отказаться от использования copy ctor. Другой - написать правильный copy ctor:

Foo (Foo const &) {}

Обычно вы хотите сделать и то, и другое.

Редактирование: Если посмотреть на это, то мой последний комментарий легко неправильно истолковать. Довольно многим классам не нужен copy ctor вообще, но если вам нужен copy ctor, он обычно должен иметь вид, приведенный выше (не явный, и принимающий const ссылку в качестве параметра).

0
ответ дан 2 December 2019 в 04:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: