У меня есть класс с конструктором копирования и конструктором, принимающим std::reference_wrapper
:
#include <functional>
#include <iostream>
class Class {
public:
Class() {
std::cout << "Class()" << std::endl;
}
Class(Class const &) {
std::cout << "Class(Class const &)" << std::endl;
}
Class(std::reference_wrapper<Class>) {
std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
}
Class(std::reference_wrapper<const Class>) {
std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
}
};
int main() {
Class a;
Class b = a;
Class c = std::ref(a);
Class d = std::cref(a);
}
Когда компилируется нормально (g++ --std=c++17 test.cpp
) это работает как нужно, вызывая четыре конструктора в последовательности:
$ ./a.exe
Class()
Class(Class const &)
Class(std::reference_wrapper<Class>)
Class(std::reference_wrapper<const Class>)
Тем не менее, компиляция с -pedantic
(Т.е. g++ --std=c++17 -pedantic test.cpp
) приводит к следующей ошибке (и другой эквивалентный для std::cref
):
test.cpp:23:22: error: conversion from 'std::reference_wrapper<Class>' to 'Class' is ambiguous
Class c = std::ref(a);
^
note: candidate: std::reference_wrapper<_Tp>::operator _Tp&() const [with _Tp = Class]
note: candidate: Class::Class(std::reference_wrapper<Class>)
Почему это (то есть, как я нарушаю стандарт, ответил в Конструктор преобразования против оператора преобразования: приоритет), а также как мне достичь результата без -pedantic
в соответствии со стандартом?
$ g++ --version
g++.exe (Rev1, Built by MSYS2 project) 7.2.0
как мне достичь результата без -педантики стандартным образом?
Создайте перегрузки с точным соответствием, в вашем случае:
Class(std::reference_wrapper<Class>&&) {
std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
}
Class(std::reference_wrapper<const Class>&&) {
std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
}
Определите конструкторы как explicit
чтобы избежать конфликта с оператором конвертации operator T& () const
определены в std::reference_wrapper
учебный класс:
#include <functional>
#include <iostream>
class Class {
public:
Class() {
std::cout << "Class()" << std::endl;
}
Class(Class const &) {
std::cout << "Class(Class const &)" << std::endl;
}
explicit Class(std::reference_wrapper<Class>) {
std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
}
explicit Class(std::reference_wrapper<const Class>) {
std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
}
};
int main() {
Class a;
Class b = a;
Class c = std::ref(a); // call Class(Class const &) trough the conversion operator
Class d(std::ref(a)); // call Class(std::reference_wrapper<Class>)
Class e = std::cref(a); // call Class(Class const &) trough the conversion operator
Class f(std::cref(a)); // call Class(std::reference_wrapper<const Class>)
}
Либо удалите перегруженные конструкторы 3 и 4, чтобы всегда использовать конструктор копирования. Class(Class const &)
,
Вы не получите ошибок без педантичной опции, потому что GCC дает приоритет копировать конструктор, а не операторы преобразования, но это не является частью стандарта, где приоритет не определен, следовательно, конфликт.