Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Deduce template parameter value from concept

I continue my C++20 concept(ual) jourrney… I would like to simplify the following code by deducing the template parameter T from the predicate argument, so that the client code does not have to precise the type of T if it can be deduced from P1.

I guess it is possible, I just don’t know the syntax: I tried various forms of template template + requires clause, but without having a successful compilation.

Any lead?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

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

template<class T, std::predicate<T> P1>
auto make_foo(P1 &&f)
{
return Foo<T, P1>(std::forward<P1>(f));
}

int main()
{
    auto fun = [](const std::string &s){return s == "toto";};
    // auto my_foo = make_foo(fun); // candidate template ignored: couldn't infer template argument 'T'
    auto my_foo = make_foo<std::string>(fun);
    return 0;
}

>Solution :

std::function has good deduction guides to get the type of a callable:

// 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>
Foo(P1 &&) -> Foo<typename single_function_argument<decltype(std::function{std::declval<P1>()})>::type, P1>;

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

// Can still specify type manually if you want
template<class T, std::predicate<T> P1>
auto make_foo(P1 &&f)
{
    return Foo<T, P1>(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);
}

The reason you have to go this round-about way is that the type of fun satisfies all of std::predicate<const std::string&>, std::predicate<const char*>, std::predicate<TypeImplicitlyConveribleToString>, there’s no unique way to get a type for T. This approach also fails with generic lambdas [](const auto& s) { return s == "toto"; }, so you would need to use make_foo<std::string>(fun).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading