user12411795
user12411795

Reputation:

make function accept function pointers or lambda functions with the correct argument types only

I've got two functions defined:

std::vector<ptr> find(const ptr&, const std::function<bool(const ptr&)>&, const std::function<bool(const ptr&)>&);

and

std::vector<ptr> find(const ptr&, const std::function<bool(const ptr&)>&, const std::function<bool(const std::vector<ptr>&)>&);

I'm trying to rewrite them as template function accepting template arguments for the functions, in order to avoid new/delete for the std::function and avoiding calling via a virtual function.

template<typename CHECK, typename DIVE>std::vector<ptr> find(const ptr&, const CHECK&, const DIVE&);

But the compiler gets confused as the template definition for both functions is identical. Is there some way to do this -- e.g. by using some static_assert that the argument must be convertable to a std::function with a certain argument set?

I'm bound to C++11...

Upvotes: 0

Views: 66

Answers (2)

user12411795
user12411795

Reputation:

implementation for DIVE argument type vector

template<typename CHECK, typename DIVE>
std::vector<ptr> findImpl(
    const ptr&pRoot,
    const CHECK&rCheck,
    const DIVE&rDive,
    const std::integral_constant<bool, true>&);

implementation for DIVE argument type ptr

template<typename CHECK, typename DIVE>
std::vector<ptr> findImpl(
    const ptr&pRoot,
    const CHECK&rCheck,
    const DIVE&rDive,
    const std::integral_constant<bool, false>&);

forwarding to the implementation matching the argument type of DIVE

template<typename CHECK, typename DIVE>
std::vector<ptr> find(const ptr&pRoot, const CHECK&rCheck, const DIVE&rDive)
{    return findImpl(
         pRoot,
         rCheck,
         rDive,
         std::integral_constant<
             bool,
             std::is_convertible<
                 DIVE,
                 std::function<bool(const std::vector<ptr>&)>
             >::value
         >()
    );
}

Upvotes: 0

user4442671
user4442671

Reputation:

Since both of your template arguments are predicates, you should use the std::predicate concept:

template<std::predicate<const ptr&> CHECK, std::predicate<const ptr&> DIVE>
std::vector<ptr> find(const ptr&, const CHECK&, const DIVE&) {
 // ...
}

Full example:

#include <concepts>
#include <vector>

struct ptr {};

template<std::predicate<const ptr&> CHECK, std::predicate<const ptr&> DIVE>
std::vector<ptr> find(const ptr&, const CHECK&, const DIVE&) {
  return {};
}


bool foo(const ptr&);
bool bar(const ptr&);

int main() {
  ptr p;

  find(p, foo, bar);
  find(p, 
       [](const ptr& p) { return true; }, 
       [](const ptr& p) { return false; }
    );
}

Upvotes: 2

Related Questions