Search code examples
c++referenceconstraintsc++-conceptsforwarding-reference

Universal reference deduction using the same_as concept


I'm trying to implement a push function for a blocking queue which accepts a universal reference as it's template parameter, but requires that the template argument be the same type as the queue's element type:

template <typename ValueType>
class shared_queue
{
public:
    template <typename Arg>
        requires std::same_as<Arg, ValueType>
    void push(Arg&& arg);
private:
    std::deque<ValueType> container_;
};

However, I'm not quite sure how is universal reference deduction supposed to work in this case, or if it works at all for that matter. The following code:

shared_queue<int> sq;
int x{ 5 };
sq.push(x); // won't compile
sq.push(5); // all good

does not compile. The compiler complains that: Compiler error, constraints not satisfied

I'm pretty sure I'm misunderstanding something but I don't know what.


Solution

  • You need to remove_reference from Arg for same_as to consider the int& to x and int the same type. You may also want to remove const in case you have const int x and pass that as a parameter. Removing both (+ volatile) can be done with std::remove_cvref_t:

    template <typename Arg>
        requires std::same_as<std::remove_cvref_t<Arg>, ValueType>
    void push(Arg&& arg) {
        container_.push_back(std::forward<Arg>(arg));
    }
    

    Another option would be to allow for any arguments that can be used to construct a ValueType:

    template <class... Args>
        requires std::constructible_from<ValueType, Args...>
    void emplace(Args&&... args) {
        container_.emplace(container_.end(), std::forward<Args>(args)...);
    }