0

I got some code working where the first template parameter was deduced from the second predicate template parameter see this question. The solution to the former question (deducing the argument type from std::function + using a deduction guide) got me reasonably far for my use case.

Now I want to extend it by adding a Policy class to the list of template parameters. Since I would like to put a default policy, it should be at the end of the template parameter list. I tried to modify the solution accordingly, but the compiler fails to deduce the Policy type.

#include<concepts>
#include<utility>
#include<string>
#include<functional>

struct Bar1{};
struct Bar2{};

template<class T, std::predicate<T> P1, class Policy=Bar1>
struct Foo : Policy
{
    P1 _f;
    Foo(P1 &&f): _f(std::forward<P1>(f)) {}
};

// Replacement for `std::function<T(U)>::argument_type`
template<typename T> struct single_function_argument;
template<typename Ret, typename Arg> struct single_function_argument<std::function<Ret(Arg)>> { using type = Arg; };

// Deduction guide
template<class P1, class Policy>
Foo(P1 &&) -> Foo<typename single_function_argument<decltype(std::function{std::declval<P1>()})>::type, P1, Policy>;

template<class P1, class Policy>
auto make_foo(P1 &&f)
{
    // Use CTAD
    return Foo<P1, Policy>(std::forward<P1>(f));
}

// Can still specify type manually if you want
template<class T, std::predicate<T> P1, class Policy>
auto make_foo(P1 &&f)
{
    return Foo<T, P1, Policy>(std::forward<P1>(f));
}

int main() {
    auto fun = [](const std::string &s){return s == "toto";};
    auto my_foo1 = Foo(fun);
    auto my_foo2 = make_foo(fun);
    auto my_foo3 = Foo<Bar1>(fun);
    auto my_foo4 = make_foo<Bar1>(fun);
    auto my_foo5 = Foo<Bar2>(fun);
    auto my_foo6 = make_foo<Bar2>(fun);
}

Fails to compile with clang 14.0:

<source>:22:1: note: candidate template ignored: couldn't infer template argument 'Policy'
Foo(P1 &&) -> Foo<typename single_function_argument<decltype(std::function{std::declval<P1>()})>::type, P1, Policy>;
^
<source>:10:8: note: candidate template ignored: could not match 'Foo<T, P1, Policy>' against '(lambda at <source>:39:16)'
struct Foo : Policy
       ^
WaterFox
  • 850
  • 6
  • 18
  • 1
    ^^^ Other than that, you are missing the template parameter in the deduction guide and make_foo: https://gcc.godbolt.org/z/8E8xjfav6 – JeJo Jun 23 '22 at 06:09
  • Beautiful! Thank you! So in short, if i have to precise the policy argument, I have to define all the others?! I have 2 more questions to get a better grasp of what is happening: why should'nt we use `Foo` ) mean? – WaterFox Jun 23 '22 at 13:46

0 Answers0