c++c++-conceptsoverload-resolution

How does the mechanism behind overloading for member function arguments in a requires expression work?


This is a follow-up question to How to apply a concept to a member function in a concept and then use it?. My focus is not on how to fix this code but on understanding the underlying mechanism.

Assume the following code (assembled from contributions from @Wutz, @Jarod42, and @wohlstad):

#include <string>
#include <string_view>

template<typename T>
concept has_set = requires(T t) {
    { t.set(
        [](){ struct {
            operator std::string_view();
            operator std::string();
            operator char *();
        } s; return s; }()
      ) } -> std::same_as<void>;
};

struct Foo {};
static_assert(!has_set<Foo>);

struct Bar {
    void set(std::string_view);
};
static_assert(has_set<Bar>);

struct Baz {
    void set(int i);
    void set(std::string) const noexcept;
};
static_assert(has_set<Baz>);

struct Bazz {
    void set(char *);
};
static_assert(has_set<Bazz>);

struct Bazzz {
    void set(char *);
    void set(std::string);
};

// Why do we have a build failure here? 
// static_assert(has_set<Bazzz>);
  1. Please explain how and why the conversion operator of the type used as an argument for t.set in the requires expression is evaluated during the instantiation of the concept.
  2. Please explain why the overload set of Bazzz yields a build failure for the concept

Solution

    1. Please explain how and why the conversion operator of the type used as an argument for t.set in the requires expression is evaluated during the instantiation of the concept.

    Like normal. The expression needs to be check to see if its valid so it goes through the normal overload resolution steps and it converts s to a type that works if able to.

    1. Please explain why the overload set of Bazzz yields a build failure for the concept

    You have an ambiguous conversion as both void set(char *); and void set(std::string); are viable since s can be converted to a char* or a std::string. Non of these conversions is better than the other so you get an error.