2

I am implementing a search algorithm with heuristic function in c++ 20. I'm trying to constrain the function my algorithm can use with a concept like so:

template<typename SelfType, unsigned from, unsigned to>
concept Heuristic = requires(SelfType h, unsigned current)
{
    { h(current) } -> unsigned;

    assert(h(to) == 0);
};

Then I can write something like:

template<unsigned from, unsigned to>
struct H
{
    unsigned operator()(unsigned current)
    {
        return to - current + 100;
    }
};

Of course the assert does not work and that is not a valid heuristic because here h(to) is 100. I want to make the compiler check in compile time that h(to) equals 0.

  • 3
    You cannot have assertions in requirements. Concepts aside, how do you expect the compiler to verify that `h(to) == 100` if `h(to)` cannot be evaluated at compile-time? (It is not a constant expression in your example because `operator()` is not `constexpr`.) – walnut Apr 17 '20 at 23:41
  • Which compiler are you using? Even if you remove the `assert`, this (`-> unsigned;`) isn't valid. The correct way to write this is with `-> std::same_as;` or `-> std::convertible_to;` – Indiana Kernick Apr 17 '20 at 23:46

1 Answers1

1

I want to make the compiler check in compile time that h(to) equals 0.

That would only be possible if the compiler was able to call h(to) at compile time. Which it can't, because there's no guarantee that whatever function gets invoked is constexpr. SelfType could be a function pointer type, and function pointers don't carry around constexpr. And concepts can't even check whether something is a constant expression or not.

When you start getting into questions of whether values map into the proper domain, or whether a function maps values into a domain, that isn't really a "concept" anymore. Or at least, it isn't a concept in the sense of the language feature.

That is, there are certain things when we consider to be requirements of a particular user of a concept which the language cannot verify. The C++20 concept library is full of these axiomatic concept requirements.

This is also a good reason why you should use a named member function for your heuristics, rather than assuming that anything which has an operator() overload that just so happens to map from unsigned integers to unsigned integers is a "heuristic".

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982