Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use concepts or SFINAE to check if class has a templated member function with a std::array parameter

Introduction

I want to detect, using concepts and/or type traits, if a class has a member function with a std::array parameter.

For example: Class below would pass the concept.

class OStreamRealizationGood
{
    template<size_t size>
    uint8_t send(std::array<uint8_t, size> array)
};

Up until now, I have used a trick for concepts. The trick is defining the size to 0. So my concept looks like this:

template<typename Candidate>
concept OStream = requires(Candidate candidate, std::array<uint8_t, 0> array)
{
    {candidate.send(array)} -> std::same_as<uint8_t>;
};

That trick works for a templated function, but it isn't really the thing that I need. It isn't the thing that I need because the class below would also comply, but I would like that it doesn't.

class OStreamRealizationBad
{
    uint8_t send(std::array<uint8_t, 0> array)
};

Question

Is there a way to write this to ensure that send(array) is a templated function?

Things I tried

I had an idea of using declval(size_t) as in the picture below, but that doesn't work for primitive types.

template<typename Candidate>
concept OStream = requires(Candidate candidate, std::array<uint8_t, declval(size_t)> array)
{
    {candidate.send(array)} -> std::same_as<uint8_t>;
};

Another idea that doesn't work was recursing the concepts:

template<typename Candidate, size_t size>
concept HasSendImpl = requires(Candidate candidate, std::array<uint8_t, size> array)
{
    {candidate.send(array)} -> std::same_as<uint8_t>;
};

template<typename Candidate>
concept HasSend = requires(size_t size)
{
        requires HasSendImpl<Candidate, size>;
};

Additional question

Additionally, I don't understand why the example above doesn't work.

like image 906
Dino Saric Avatar asked Nov 07 '22 02:11

Dino Saric


1 Answers

Is there a way to write this to ensure that send(array) is a templated function?

You can use the template keyword in the constraint to signify that send needs to be a template function:

template<typename T, std::size_t size>
concept GoodRealization = requires(T t, std::array<uint8_t, size> array) {
    { t.template send<size>(array) } -> std::same_as<uint8_t>;
};

DEMO.

Note that this will not reject a type that overloads send with a non-template and a template function: of both are viable candidates in overload resolution, the non-template overload could be the best candidate (given the regular rules of overload resolution).

like image 194
dfrib Avatar answered Nov 15 '22 12:11

dfrib