I have the following concept:
template<typename T, typename U>
concept MaybeConst = std::is_same_v<U, std::remove_cv_t<T>>;
And a use-case for it looks like this (it's and example you can actually try):
#include <type_traits>
template<typename T, typename U>
concept MaybeConst = std::is_same_v<U, std::remove_cv_t<T>>;
class String {};
class Value {
protected:
double number = 0;
public:
Value & operator=(const Value & value) {
number = value.number;
return *this;
}
Value & operator=(const wchar_t * value) {
number = 0;
return *this;
}
Value & operator=(MaybeConst<String> auto & value) {
number = 0;
return *this;
}
};
String getString() {
return {};
}
int main(int argc, char * argv[]) {
Value someValue;
someValue = getString();
return 0;
}
In the end, the compiler doesn't even count operator=(MaybeConst<String> auto & value)
as an option when matching definitions and arguments.
It just says it's ambiguous what to chose between operator=(const Value & value)
and operator=(const wchar_t * value)
:
ambiguous overload for ‘operator=’ (operand types are ‘Value’ and ‘String’)
note: candidate: ‘Value& Value::operator=(const Value&)’
note: candidate: ‘Value& Value::operator=(const wchar_t*)’
The only compiler flag is -fconcepts
.
You want to bind an rvalue to auto &
. This will not work since the auto
will never deduce to a const-qualified type for a non-const rvalue (auto &
is meant for lvalues). You want to use a forwarding reference instead:
template<typename T> requires MaybeConst<std::remove_reference_t<T>, String>
Value & operator=(T && value) {
number = 0;
return *this;
}
// Or
template<typename T, typename U>
concept IsSameDecayed = std::is_same_v<U, std::remove_cvref_t<T>>;
Value & operator=(IsSameDecayed<String> auto && value) {
number = 0;
return *this;
}
Or you can just have a two overloads:
private:
void assign_string(auto & value) {
// decltype(value) is `const String&` or `String&`
}
public:
Value & operator=( String & value) { assign_string(value); return *this; }
Value & operator=(const String & value) { assign_string(value); return *this; }
Where someValue = getString();
will pick the const String &
overload