I have a class with both a copy constructor and a constructor taking a 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);
}
When compiled normally (g++ --std=c++17 test.cpp
) this works as desired, calling the four constructors in sequence:
$ ./a.exe
Class()
Class(Class const &)
Class(std::reference_wrapper<Class>)
Class(std::reference_wrapper<const Class>)
However, compiling with -pedantic
(i.e., g++ --std=c++17 -pedantic test.cpp
) results in the following error (and another equivalent one for the 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>)
Why is this (i.e., how am I violating the standard, answered in Conversion constructor vs. conversion operator: precedence), and how do I achieve the result without -pedantic
in a standard-conforming manner?
$ g++ --version
g++.exe (Rev1, Built by MSYS2 project) 7.2.0
std::ref
returns an rvalue, so an lvalue reference would be ineligible and thus remove the ambiguity; I would think an rvalue reference would still be ambiguous, but maybe it's a better match during overload resolution (if so I'm not sure why). – Roterstd::ref
/std::cref
should call the constructors taking astd::reference_wrapper
. – Tabb