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

Constrain function return type without specifying function parameters

I was trying to constrain the return type of client-provided functions without asking to specify the function parameters:

#include <type_traits>

template <typename T>
struct ReturnTypeWrapper {};

template <typename R, typename... Args>
struct ReturnTypeWrapper<R(Args...)> {
    using type = R;
};

template <typename T>
concept ReturnVoid = std::is_same_v<void, typename ReturnTypeWrapper<T>::type>;

template <auto c>
requires(ReturnVoid<decltype(c)>)
void g() {}

void foo(double, int){};

int main() {
    static_assert(std::is_same_v<void, typename ReturnTypeWrapper<decltype(foo)>::type>);
    g<foo>();
    return 0;
}

While there is no problem with the static_assert, when it comes to instantiating g with the foo function, I have the following compile error:

xxx/Concept.cpp: In function ‘int main()’:
xxx/Concept.cpp:24:11: error: no matching function for call to ‘g<foo>()’
   24 |     g<foo>();
      |     ~~~~~~^~
xxx/Concept.cpp:17:6: note: candidate: ‘template<auto c>  requires  ReturnVoid<decltype(c)> void g()’
   17 | void g() {}
      |      ^
xxx/Concept.cpp:17:6: note:   template argument deduction/substitution failed:
xxx/Concept.cpp:17:6: note: constraints not satisfied
xxx/Concept.cpp: In substitution of ‘template<auto c>  requires  ReturnVoid<decltype(c)> void g() [with auto c = foo]’:
xxx/Concept.cpp:24:11:   required from here
xxx/Concept.cpp:13:9:   required for the satisfaction of ‘ReturnVoid<decltype (c)>’ [with c = &foo()]
xxx/Concept.cpp:13:27: error: no type named ‘type’ in ‘struct ReturnTypeWrapper<void (*)(double, int)>’
   13 | concept ReturnVoid = std::is_same_v<void, typename ReturnTypeWrapper<T>::type>;
      |                      ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[3]: *** [cpp/Template/CMakeFiles/template-concept.dir/build.make:76: cpp/Template/CMakeFiles/template-concept.dir/Concept.cpp.o] Error 1
make[2]: *** [CMakeFiles/Makefile2:5580: cpp/Template/CMakeFiles/template-concept.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:5587: cpp/Template/CMakeFiles/template-concept.dir/rule] Error 2
make: *** [Makefile:1941: template-concept] Error 2

It appears that only the primary template is chosen rather than the specialized one for function pointers. Why is it so? Am I on the right track to constrain function return type without specifying parameters?

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

PS: Compiler is gcc 11.3.0.

>Solution :

template <auto c>
    requires (ReturnVoid<decltype(c)>)
void g() {}

The issue here is that when you call g<foo>(), what you get for c isn’t void(double, int) – because you can’t have values of function style. You get a function-to-pointer conversion, so c is actually a void(*)(double, int). This doesn’t match your specialization for ReturnTypeWrapper which only handled the pattern R(Args...).

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