Member function template deduction isn't working - c++

I'm writing a class that wraps a member function while allowing for type-erasure.
#include <utility>
template<typename T>
class FunctionWrapper;
template<typename Ret, typename...Args>
class FunctionWrapper<Ret(Args...)> {
public:
template<typename T>
FunctionWrapper(T& object_reference, Ret(T::*function_ref)(Args...)) :
object_ptr(&object_reference), callable(&static_method<T, function_ref>) {}
private:
typedef Ret (*callable_type)(void*, Args...);
void* object_ptr;
callable_type callable;
Ret operator()(Args&&...args) {
callable(object_ptr, std::forward<Args>(args)...);
}
template<typename T, Ret(T::*function_ref)(Args...)>
Ret static static_method(void* object_ptr, Args...args) {
T* obj = static_cast<T*>(object_ptr);
return (obj->*function_ref)(args...);
}
};
struct S {
void add() {}
};
template<typename T, typename Ret, typename... Args>
auto static get_function_wrapper(T& object_ref, Ret(T::*function_ref)(Args...)) {
return FunctionWrapper<Ret(Args...)>(object_ref, function_ref);
}
int main() {
S s;
const auto shallow_function = get_function_wrapper(s, &S::add);
}
But I'm receiving an error saying that the deduced static_method is not a callable_type which I don't understand.
<source>: In instantiation of 'FunctionWrapper<Ret(Args ...)>::FunctionWrapper(T&, Ret (T::*)(Args ...)) [with T = S; Ret = void; Args = {}]':
<source>:38:12: required from 'auto get_function_wrapper(T&, Ret (T::*)(Args ...)) [with T = S; Ret = void; Args = {}]'
<source>:43:55: required from here
<source>:12:40: error: no matches converting function 'static_method' to type 'FunctionWrapper<void()>::callable_type' {aka 'void (*)(void*)'}
12 | object_ptr(&object_reference), callable(&static_method<T, function_ref>) {}
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:25:17: note: candidate is: 'template<class T, void (T::* function_ref)()> static Ret FunctionWrapper<Ret(Args ...)>::static_method(void*, Args ...) [with Ret (T::* function_ref)(Args ...) = T; Ret = void; Args = {}]'
25 | Ret static static_method(void* object_ptr, Args...args) {
| ^~~~~~~~~~~~~
Execution build compiler returned: 1
I don't understand why this isn't working

Related

SFINAE doesn't work in recursive function

Let's create currying function.
template <typename TFunc, typename TArg>
class CurryT
{
public:
CurryT(const TFunc &func, const TArg &arg)
: func(func), arg(arg )
{}
template <typename... TArgs>
decltype(auto) operator()(TArgs ...args) const
{ return func(arg, args...); }
private:
TFunc func;
TArg arg ;
};
template <typename TFunc, typename TArg>
CurryT<decay_t<TFunc>, remove_cv_t<TArg>>
Curry(const TFunc &func, const TArg &arg)
{ return {func, arg}; }
And function that decouple function to single argument functions:
// If single argument function (F(int)).
template <typename F>
static auto Decouple(const F &f, enable_if_t<is_invocable_v<F, int>> * = nullptr)
{
return f;
}
// If multiple arguments function (F(int, int, ...)).
template <typename F>
static auto Decouple(const F &f, enable_if_t<!is_invocable_v<F, int>> * = nullptr)
{
return [f](int v) { return Decouple( Curry(f, v) ); };
}
Everything works fine if 2 arguments function is passed:
auto f1 = Decouple(
[](int a, int b)
{ std::cout << a << " " << b << std::endl; }
);
f1(3)(4); // Outputs 3 4
But if I add more arguments
auto f2 = Decouple(
[](int a, int b, int c)
{ std::cout << a << " " << b << " " << c << std::endl; }
);
f(5)(6)(7);
The compilation breaks: https://coliru.stacked-crooked.com/a/10c6dba670d17ffa
main.cpp: In instantiation of 'decltype(auto) CurryT<TFunc, TArg>::operator()(TArgs ...) const [with TArgs = {int}; TFunc = main()::<lambda(int, int, int)>; TArg = int]':
main.cpp:17:26: error: no match for call to '(const main()::<lambda(int, int, int)>) (const int&, int&)'
17 | { return func(arg, args...); }
It breaks in instantiation of std::is_invocable.
Since debugging the standard library is hard, I created simple versions of standard type traits classes:
template <typename F> true_type check(const F &, decltype( declval<F>()(1) )* );
template <typename F> false_type check(const F &, ...);
template <typename F>
struct invocable_with_int : decltype(check(declval<F>(), nullptr))
{};
template <typename F>
inline constexpr bool invocable_with_int_v = invocable_with_int<F>::value;
template<bool B>
struct my_enable_if {};
template<>
struct my_enable_if<true>
{ using type = void; };
template <bool B>
using my_enable_if_t = typename my_enable_if<B>::type;
The problem remains the same https://coliru.stacked-crooked.com/a/722a2041600799b0:
main.cpp:29:73: required by substitution of 'template<class F> std::true_type check(const F&, decltype (declval<F>()(1))*) [with F = CurryT<main()::<lambda(int, int, int)>, int>]'
It tries to resolve calling to this function:
template <typename F> true_type check(const F &, decltype( declval<F>()(1) )* );
But decltype (declval<F>()(1))*) fails. But shouldn't this function be removed from overload resolution because template substitution fails? It works when Decouple is called first time. But when it is called second time the SFINAE seems to be disabled, and the first failure of template substitution gives a compilation error. Are there some limitation on secondary SFINAE? Why calling template function recursively doesn't work?
The problem is reproduced in GCC and Clang. So it is not a compiler bug.
Your operator() overload is completely unconstrained and therefore claims to be callable with any set of arguments. Only declarations, not definitions, are inspected to determine which function to call in overload resolution. If substitution into the definition then fails, SFINAE does not apply.
So, constrain your operator() to require TFunc to be callable with TArg and TArgs... as arguments.
For example:
template <typename... TArgs>
auto operator()(TArgs ...args) const -> decltype(func(arg, args...))
For me it is strange that your CurryT::operator() accepts unknown number of arguments.
Since aim is to have a functions which accept only one argument I expected that this function will accept only one argument.
IMO depending what kind of function CurryT holds CurryT::operator() should return a different type: return type of starting function or another version of CurryT.
Here is my approach using std::bind_front from C++20:
namespace detail {
template <typename TFunc>
class CurryT
{
public:
explicit CurryT(TFunc f) : mF(std::move(f))
{}
template<typename T>
auto get(T&& x, int = 0) -> decltype(std::declval<TFunc>()(x)) {
return mF(x);
}
template<typename T>
auto get(T&& x, char) {
return CurryT<decltype(std::bind_front(mF, std::forward<T>(x)))>{
std::bind_front(mF, std::forward<T>(x))
};
}
template<typename T>
auto operator()(T&& x)
{
return this->get(std::forward<T>(x), 1);
}
private:
TFunc mF;
};
}
template<typename F>
auto Decouple(F&& f)
{
return detail::CurryT<std::decay_t<F>>{std::forward<F>(f)};
}
https://godbolt.org/z/eW9r4Y6Ea
Note with this approach integer argument is not forced like in your solution.

Why can't I deduce the function signature for a mutable lambda?

I have the following code which implements a memoize function.
note The question is not about how to write a memoize function specifically but rather about the compile error I get with this implementation and the smallest change to get it to work.
The implementation.
#include <functional>
#include <map>
#include <functional>
#include <iostream>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
template <typename ReturnType, typename... Args>
std::function<ReturnType (Args...)>
memoizeImp(std::function<ReturnType (Args...)> func)
{
std::map<std::tuple<Args...>, ReturnType> cache;
return ([=](Args... args) mutable {
std::tuple<Args...> t(args...);
if (cache.find(t) == cache.end())
cache[t] = func(args...);
return cache[t];
});
}
template <typename Fn>
auto memoize(Fn && fn){
return memoizeImp(FFL(fn));
}
and test program
int main()
{
auto a = 2.;
auto foo = [a](double x){return x+a;};
auto foom = memoize(foo);
std::cout << foo(1) << std::endl;
std::cout << foom(1) << std::endl;
}
the output as expected is
3
3
However if I make a small change to the test program changing
auto foo = [a](double x){return x+a;};
to
auto foo = [a](double x)mutable{return x+a;};
I get the following compile error on gcc
Could not execute the program
Compiler returned: 1
Compiler stderr
<source>: In instantiation of 'auto memoize(Fn&&) [with Fn = main()::<lambda(double)>&]':
<source>:49:24: required from here
<source>:42:26: error: invalid use of void expression
42 | return memoizeImp(FFL(fn));
| ~~~^~~~
<source>: In instantiation of 'typename memfun_type<decltype (& F::operator())>::type FFL(const F&) [with F = main()::<lambda(double)>; typename memfun_type<decltype (& F::operator())>::type = void; decltype (& F::operator()) = double (main()::<lambda(double)>::*)(double)]':
<source>:42:26: required from 'auto memoize(Fn&&) [with Fn = main()::<lambda(double)>&]'
<source>:49:24: required from here
<source>:24:12: error: return-statement with a value, in function returning 'memfun_type<double (main()::<lambda(double)>::*)(double)>::type' {aka 'void'} [-fpermissive]
24 | return func;
| ^~~~
The failing code and compile error can be viewed and tested at https://godbolt.org/z/74PKWvqr4
I'm not sure what the fix is to make it work with mutable lambdas.
You are lacking a specialisation.
Adding this makes it work
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...)>
{
using type = std::function<Ret(Args...)>;
};
The operator() of the closure-type of a lambda is const qualified iff the lambda is not declared mutable

C++ Recursive Variadic Templates with extendes Base case

i want to use recursive variadic templates with a base case with more than 2 types. The following example does not compile. What could be the problem?
My expectation was that f<int, int>(5) would call a case like:
[with T = int; Arg = int; Args = {int}]
but that seems to be no option for the compiler (g++ c++17) ;)
template<class T, typename Arg, typename... Args>
void f(T a) {
}
template<class T, typename Arg>
void f (T a) {
}
int main() {
f<int, int>(5);
return 0;
}
<source>: In function 'int main()':
<source>:11:18: error: call of overloaded 'f<int, int>(int)' is ambiguous
11 | f<int, int>(5);
| ^
<source>:2:6: note: candidate: 'void f(T) [with T = int; Arg = int; Args = {}]'
2 | void f(T a) {
| ^
<source>:6:6: note: candidate: 'void f(T) [with T = int; Arg = int]'
6 | void f (T a) {
| ^
Compiler returned: 1
You can combine both cases and use a constexpr if statement in the function template:
#include <iostream>
template<class T, typename Arg, typename... Args>
void f(T a) {
std::cout << sizeof...(Args) << '\n';
if constexpr (sizeof...(Args) > 0) {
f<T, Args...>(a);
}
}
int main() {
f<int, int>(5);
std::cout << "---\n";
f<int, int, double, float, int>(5);
}
Output:
0
---
3
2
1
0

How to do variadic deduction in std::function's parameters?

I try to implement a function f: (std::function -> int) which will pass 1s into input_functor
with c++ variadic template.
Let input_functor be g.
For example:
If g is std::function<int(int,int)>, then f return g(1, 1).
If g is std::function<int(int,int,int)>, then f return g(1, 1, 1).
If g is std::function<int(int,int,int,int)>, then f return g(1, 1, 1, 1).
#include <functional>
#include <iostream>
template <typename T, typename... Args>
int apply(std::function<int(T, Args...)> func) {
auto tmp = [func](Args... args) {
return func(1, args...);
};
return apply(tmp);
}
template <typename T>
int apply(std::function<int(T)> func) {
return func(1);
}
int main() {
std::function<int(int, int)> f = [](int a, int b) {
return a + b;
};
std::cout << apply(f) << "\n";
return 0;
}
The compiler (clang++) error msg is that it cannot match candidates.
main.cpp:9:12: error: no matching function for call to 'apply'
return apply(tmp);
^~~~~
main.cpp:21:18: note: in instantiation of function template specialization 'apply<int, int>' requested here
std::cout << apply(f) << "\n";
^
main.cpp:5:5: note: candidate template ignored: could not match 'function<int (type-parameter-0-0, type-parameter-0-1...)>' against
'(lambda at main.cpp:6:16)'
int apply(std::function<int(T, Args...)> func) {
^
main.cpp:13:5: note: candidate template ignored: could not match 'function<int (type-parameter-0-0)>' against '(lambda at main.cpp:6:16)'
int apply(std::function<int(T)> func) {
^
1 error generated.
You have 2 issues:
definition order:
template <typename T>
int apply(std::function<int(T)> func) {
return func(1);
}
should be place before the recursive function to allow to be visible and ends recursion.
lambda is not a std::function, so deduction don't happen
template <typename T, typename... Args>
int apply(std::function<int(T, Args...)> func) {
auto tmp = std::function{[func](Args... args) { // C++17 CTAD
return func(1, args...);
}};
return apply(tmp);
}
Demo C++17
As you are limited to C++11, you might create traits to know which std::function is needed:
template <typenate T, typename Discarded>
struct always_first
{
using type = T;
};
template <typenate T, typename Discarded> using always_first_t = typename always_first<T, Discarded>::type;
// possibly directly
// template <typenate T, typename Discarded> using always_first_t = T;
// but old compilers might have some issues with that construct as std::void_t
and then
std::function<int(always_first_t<int, Args>...)> tmp = /* your lambda */;

C++17: map type to integer value at compile time

I have the following types:
struct A { };
struct B { };
struct C { };
template <typename Class, uint16_t i>
struct def {
using message_type = Class;
static constexpr uint16_t tag = i;
};
and this tuple:
constexpr auto types = std::make_tuple(def<A, 1>(), def<B, 2>(), def<C, 3>());
Types A, B and C should be mapped to corresponding values (A -> 1 etc.). I want to create something (function, struct) that given object of one of these types will return proper value. I tried doing the following:
template <typename T>
struct gettag {
static decltype(T::tag) value(typename T::message_type const&) { return T::tag; }
};
template <typename... Args>
struct tagdb : public gettag<Args>... {
tagdb(std::tuple<Args...> const& t) { }
};
int main() {
tagdb t(types);
A a;
std::cout << t.value(a) << '\n';
}
This does not work, g++ claims that request for member value is ambiguous:
x.cc: In function ‘int main()’:
x.cc:29:17: error: request for member ‘value’ is ambiguous
29 | std::cout << t.value(a) << '\n';
| ^~~~~
x.cc:16:26: note: candidates are: ‘static decltype (T::tag) gettag<T>::value(const typename T::message_type&) [with T = def<C, 3>; decltype (T::tag) = const short unsigned int; typename T::message_type = C]’
16 | static decltype(T::tag) value(typename T::message_type const&) { return T::tag; }
| ^~~~~
x.cc:16:26: note: ‘static decltype (T::tag) gettag<T>::value(const typename T::message_type&) [with T = def<B, 2>; decltype (T::tag) = const short unsigned int; typename T::message_type = B]’
x.cc:16:26: note: ‘static decltype (T::tag) gettag<T>::value(const typename T::message_type&) [with T = def<A, 1>; decltype (T::tag) = const short unsigned int; typename T::message_type = A]’
I am a little surprised, especially since it clearly shows that each method is parameterized using different types.
Is there a way to make this solution work or should I completely change my approach? Note that what I want to avoid most is writing overloads for each type.
I suggest a solution without a std::tuple and gettag:
struct A { };
struct B { };
struct C { };
template <typename Class, std::uint16_t i>
struct def {
static constexpr std::uint16_t value(Class) {
return i;
}
};
template <typename... Tags>
struct tagdb : public Tags... {
using Tags::value...;
};
template<class... Tags>
constexpr auto make_tagdb(Tags...) {
return tagdb<Tags...>{};
}
// template<class... Tags>
// constexpr auto make_tagdb(std::tuple<Tags...>) {
// return tagdb<Tags...>{};
// }
constexpr auto tags = make_tagdb(def<A, 1>(), def<B, 2>(), def<C, 3>());
int main() {
A a;
std::cout << tags.value(a) << '\n'; // Output: 1
}
The problem is that you have template base classes, all of which declare a member with the same name. The easiest fix is just to pull all the base class value functions into the derived class:
using gettag<Args>::value...;
See https://godbolt.org/z/F_Prhg