Идеальный конструктор пересылки и удаленные конструкторы

Как указал Майкл Парк добавление идеальных конструкторов переадресации может быть сложным, если мы не хотим оказаться в неправильном конструкторе.

В настоящее время у меня есть класс A, который использует идеальный конструктор пересылки, и поэтому мне нужно явно объявить 4 конструктора: A&, const A&, A&& и const A&&:

class A
{
public:
    template<typename T> A(T&&);
    A(A&);
    A(const A&);
    A(A&&);
    A(const A&&);
};

Я хотел бы запретить использование конструктора const reference rvalue, поэтому я рассматриваю возможность его удаления:

class A
{
public:
    template<typename T> A(T&&);
    A(A&);
    A(const A&);
    A(A&&);
    A(const A&&) = delete;
};

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

Возможно ли, что идеальный пересылающий конструктор заменит удаленный конструктор? Ведь универсальная ссылка T&& совместима с const A&&.


person vdavid    schedule 13.08.2019    source источник
comment
Я бы предложил противоположный подход. Используйте SFINAE, чтобы ограничить конструктор пересылки и сохранить значения по умолчанию, предоставленные компилятором.   -  person NathanOliver    schedule 13.08.2019
comment
Идеальное перенаправление конструктора неявного преобразования из чего-либо кажется вам чем-то, чего вы, возможно, не хотите иметь?   -  person Öö Tiib    schedule 13.08.2019
comment
@NathanOliver, могу ли я использовать SFINAE, чтобы сказать компилятору принимать все, кроме A, в конструкторе пересылки?   -  person vdavid    schedule 13.08.2019
comment
template<typename T, std::enable_if_t<!std::is_same_v<T, A>, bool> = true> говорит использовать это только тогда, когда T не является A.   -  person NathanOliver    schedule 13.08.2019
comment
@ÖöTiib На самом деле цель состоит в том, чтобы работать с чем угодно, так что да, боюсь, это то, чего я хочу.   -  person vdavid    schedule 13.08.2019
comment
@NathanOliver Спасибо, попробую. Но даже если это сработает, вопрос остается открытым, т.е. я хотел бы знать, гарантированно ли явное удаление конструктора запретит вызов эквивалентной подписи с пересылающим конструктором.   -  person vdavid    schedule 13.08.2019
comment
@vdavid А. Ну, у вас есть ответ на это ниже. Если есть конструктор точного соответствия, он всегда предпочтительнее шаблонного. Удаление проверяется после завершения разрешения перегрузки, поэтому вы гарантированно получите ошибку. Я думаю, что у меня есть обманная цель для этого, дайте мне посмотреть.   -  person NathanOliver    schedule 13.08.2019
comment
Это вопрос, о котором я думал. Недостаточно хорошо, чтобы быть мишенью для дублирования, но подтверждает, что удаленные конструкторы являются частью разрешения перегрузки и будут вызываться, если они лучше всего подходят.   -  person NathanOliver    schedule 13.08.2019


Ответы (1)


Конструкторы с идеальной переадресацией обычно лучше подходят для неконстантных lvalue.

Возможно ли, что идеальный пересылающий конструктор заменит удаленный конструктор?

Нет. A(const A&&) — это идеальное совпадение, и оно явно удалено, поэтому, если мы попытаемся создать A из константной ссылки lvalue, будет выдана ошибка времени компиляции.

Тем не менее, вы можете сделать что-то подобное template<typename T, typename = typename std::enable_if<!std::is_same_v<A&&, T>> A(T&&);.

P.S. Хорошей практикой является пометка ваших конструкторов explicit (особенно когда происходит вывод типа).

person Nestor    schedule 13.08.2019
comment
Разве нам не нужен ни std::enable_if_t<!std::is_same_v<A&&, T> (enable_if_t вместо enable_if), ни std::enable_if<!std::is_same_v<A&&, T>::type? - person vdavid; 13.08.2019
comment
@vdavid Есть много способов сделать это. Тот, который я предоставил, очень близок к Мейерсу (Effective Modern C++, Item 27). Вот еще одно решение template <typename T, typename std::enable_if_t< !std::is_same_v<int, T>>* = 0>. - person Nestor; 13.08.2019