Неоднозначный конструктор, принимающий std :: reference_wrapper при компиляции с -pedantic - PullRequest
0 голосов
/ 02 мая 2018

У меня есть класс с конструктором копирования и конструктором, принимающим 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

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Определите конструкторы как 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 отдает предпочтение копированию конструктора, а не операторам преобразования, но это не является частью стандарта, где приоритет не определен, следовательно, конфликт.

0 голосов
/ 02 мая 2018

как мне достичь результата без -педантики стандартным образом?

Создание перегрузок с точным соответствием, в вашем случае:

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;
}

Демо

...