SFINAE doesn't work in recursive function - c++

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.

Related

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 */;

is_invocable with arbitrary function argument types

Is there a way to use std::is_invocable with arbitrary function arguments types, something like: std::is_invocable<Function, auto>. The idea is to check whether Function can accept 1 argument, regardless of the type of the argument. For a use case consider two lambdas: auto lambda1 = [](auto x) {...}, auto lambda2 = [](auto x, auto y) {...}, and a higher order templated function:
// specialize for 1 argument
template<typename Function, std::enable_if_t<(std::is_invocable<Function, auto>::value && !std::is_invocable<Function, auto, auto>::value)>, bool> = true>
void higherOrderFunc(Function&& func);
// specialize for 2 arguments
template<typename Function, std::enable_if_t<std::is_invocable<Function, auto, auto>::value, bool> = true>
void higherOrderFunc(Function&& func);
The !std::is_invocable<Function, auto, auto>::value in the first case is to prevent ambiguity for overloaded functions (that is, the preferred specialization in this case would be the 2 argument one in case of ambiguity).
Note that I am aware that auto cannot be used like this in this case. I am asking whether there's a way to implement this behaviour (at least partially).
Maybe not a perfect solution... but you can try with a passepartout
struct passepartout
{
template <typename T>
operator T & ();
template <typename T>
operator T && ();
};
Observe that conversion operators are only declared, not defined; so this structure can be used in decltype() and with std::declval() (and std::is_invocable) but can't be instantiated.
Now you can write your higherOrderFunc passing reference to passepartout to std::is_invocable.
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &>
&& ! std::is_invocable_v<F, passepartout &, passepartout &>, bool>
= true>
void higherOrderFunc (F)
{ std::cout << "-- one parameter callable" << std::endl; }
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &, passepartout &>, bool> = true>
void higherOrderFunc (F)
{ std::cout << "-- two parameter callable" << std::endl; }
The trick is that if a callable waits for auto (or auto &, or auto &&), the type is deduced as passepartout itself; when the callable wait a specific type (int, with or without references, in the following examples), the template operator T & () (or operator T && (), according the cases) is compatible (in a sense) with the expected type.
The following is a full compiling example
#include <type_traits>
#include <iostream>
struct passepartout
{
template <typename T>
operator T & ();
template <typename T>
operator T && ();
};
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &>
&& ! std::is_invocable_v<F, passepartout &, passepartout &>, bool>
= true>
void higherOrderFunc (F)
{ std::cout << "-- one parameter callable" << std::endl; }
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &, passepartout &>, bool> = true>
void higherOrderFunc (F)
{ std::cout << "-- two parameter callable" << std::endl; }
int main ()
{
auto l1a = [](auto &&){};
auto l1b = [](int &){};
auto l2a = [](auto &, int &&){};
auto l2b = [](auto, int const &){};
auto l2c = [](auto &&, auto const &){};
auto l2d = [](int &&, auto const &, auto && ...){};
higherOrderFunc(l1a);
higherOrderFunc(l1b);
higherOrderFunc(l2a);
higherOrderFunc(l2b);
higherOrderFunc(l2c);
higherOrderFunc(l2c);
higherOrderFunc(l2d);
}

How to Deduce Argument List from Function Pointer?

Given two or more example functions, is it possible to write templated code which would be able to deduce the arguments of a function provided as a template parameter?
This is the motivating example:
void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}
void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}
template<void(*Func)(/*???*/)>
struct wrapper {
using Args = /*???*/;
void operator()(Args&& ... args) const {
Func(std::forward<Args>(args)...);
}
};
int main() {
wrapper<do_something> obj; //Should be able to deduce Args to be [int, double]
obj(5, 17.4); //Would call do_something(5, 17.4);
wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int]
double value = 5;
obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70);
}
In both uses of /*???*/, I am trying to work out what I could put there that would enable this kind of code.
The following doesn't appear to work, due to Args not being defined before its first use (along with what I have to assume are numerous syntax errors besides), and even if it did, I'm still looking for a version that doesn't require explicit writing of the types themselves:
template<void(*Func)(Args ...), typename ... Args)
struct wrapper {
void operator()(Args ...args) const {
Func(std::forward<Args>(args)...);
}
};
wrapper<do_something, int, double> obj;
With C++17 we can have auto template non-type parameters which make possible the Wrapper<do_something> w{} syntax 1).
As for deducing Args... you can do that with a specialization.
template <auto* F>
struct Wrapper {};
template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<F>
{
auto operator()(Args... args) const
{
return F(args...);
}
};
Wrapper<do_something> w{};
w(10, 11.11);
1) Without C++17 it's impossible to have the Wrapper<do_something> w{} nice syntax.
The best you can do is:
template <class F, F* func>
struct Wrapper {};
template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<Ret (Args...), F>
{
auto operator()(Args... args) const
{
return F(args...);
}
};
Wrapper<declype(do_something), do_something> w{};
With C++17, you can do this:
template <auto FUNC, typename = decltype(FUNC)>
struct wrapper;
template <auto FUNC, typename RETURN, typename ...ARGS>
struct wrapper<FUNC, RETURN (*)(ARGS...)> {
RETURN operator()(ARGS ...args) {
return FUNC(args...);
}
};
I've learned this technique from W.F.'s answer
Further improvement of C++17 version: less template parameters and proper noexcept annotation:
template<auto VFnPtr> struct
wrapper;
template<typename TResult, typename... TArgs, TResult ( * VFnPtr)(TArgs...)> struct
wrapper<VFnPtr>
{
TResult
operator ()(TArgs... args) const noexcept(noexcept((*VFnPtr)(::std::forward<TArgs>(args)...)))
{
return (*VFnPtr)(::std::forward<TArgs>(args)...);
}
};
With C++11 you can consider a templated make_wrapper helper function. However, with this approach the function pointer is not a template parameter. Instead, the function pointer is "carried" by the non-static data member called f_ in the following example:
#include <iostream>
void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}
void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}
template<class Ret, class... Args>
using function_pointer = Ret(*)(Args...);
template<class Ret, class... Args>
struct wrapper {
using F = function_pointer<Ret, Args...>;
F f_;
explicit constexpr wrapper(F f) noexcept : f_{f} {}
template<class... PreciseArgs>// not sure if this is required
Ret operator()(PreciseArgs&&... precise_args) const {
return f_(std::forward<PreciseArgs>(precise_args)...);
}
};
template<class Ret, class... Args>
constexpr auto make_wrapper(
function_pointer<Ret, Args...> f
) -> wrapper<Ret, Args...> {
return wrapper<Ret, Args...>(f);
}
int main() {
constexpr auto obj = make_wrapper(do_something);
obj(5, 17.4);
constexpr auto obj2 = make_wrapper(do_something_else);
double value = 5;
obj2("Hello there!", value, 70);
return 0;
}

Implicit conversions with variadic templates

Consider two function calls
foo({"a", 1}, {"b", "value"});
foo({"a", 1}, {"b", "value"}, {"c", 1.0});
Is there a way to write function foo for arbitrary number of argument pairs?
I was thinking something along the lines
template <typename... Args>
void foo(std::pair<const char*, Args>&&...);
which unfortunately does not work.
gcc fails with an error:
error: too many arguments to function 'void foo(std::pair<const char*, Args>&& ...) [with Args = {}]'
foo({"aa", 1});
Try to simplify a bit your example and consider this:
#include<utility>
template<typename T>
void foo(std::pair<char*, T>) {}
int main() {
foo({"a", 1});
}
It doesn't compile, as you can see.
The problem is that { "a", 1 } is not a std::pair, even if you can construct one from it as it follows:
#include<utility>
void foo(std::pair<char*, int>) {}
int main() {
foo({"a", 1});
}
The error is quite clear:
couldn't infer template argument 'T'
Why can't you?
Te compiler could construct such a pair once T is known. Anyway, T must be deduced and the compiler cannot do that because { "a", 1 } is not a pair from which it can be deduced.
Anyway, { "a", 1 } can be converted to a pair, in the specific case to a specialization of std::pair<char *, T>, but first of all T must be deduced.
Deduced from what? A pair, of course, but you don't have a pair yet.
And so on, in a loop.
Let's discuss now your attempt to do something similar that involves a variadic template: it goes without saying that, if even the simpler example shown above doesn't compile, its variadic extension (if any) would not compile as well for more or less the same reason.
Is there a way to write function foo for arbitrary number of argument pairs?
I would say no, unless you use pairs as arguments for foo.
It follows a minimal, working example:
#include<utility>
template <typename... Args>
void foo(std::pair<const char*, Args>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair("b", "value"));
}
If you prefer, you can also deduce the first argument, as long as its type is fixed:
#include<utility>
template <typename T, typename... Args>
void foo(std::pair<T, Args>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair("b", "value"));
}
Otherwise you can do this if it's not fixed:
#include<utility>
template <typename... First, typename... Second>
void foo(std::pair<First, Second>&&...) {}
int main() {
foo(std::make_pair("a", 1), std::make_pair(0, "value"));
}
Is there a way to write function foo for arbitrary number of argument
pairs?
There are some solutions based on variadic templates but arguments must be pairs to allow compiler to deduce types. Then something like this might work:
template<typename... Args>
void foo() {}
template<typename T, typename U, typename... Args>
void foo(const std::pair<T, U>& p, Args... args) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
foo(args...);
}
So for:
foo(std::make_pair("a", 1), std::make_pair("b", "value"), std::make_pair("c", 1.0));
The output (with clang 3.8) is:
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = int, Args = <std::__1::pair<const char *, const char *>, std::__1::pair<const char *, double>>]
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = const char *, Args = <std::__1::pair<const char *, double>>]
void foo(const std::pair<T, U> &, Args...) [T = const char *, U = double, Args = <>]
Here is the full working example.
To expand a bit on Edgar Rokyan's answer, you can move the pair creation into the foo function:
template<typename... Args>
void foo() {}
// Forward declaration
template<typename U, typename... Args>
void foo(const char * str, U u, Args... args);
// When given a pair
template<typename U, typename... Args>
void foo(const std::pair<const char *, U>& p, Args... args) {
std::cout << p.first << " = " << p.second << std::endl;
foo(args...);
}
// when given a C string and something else, make a pair
template<typename U, typename... Args>
void foo(const char * str, U u, Args... args) {
foo(std::make_pair(str, u), args...);
}
Then you can call it like:
foo("hi", 42,
"yo", true,
std::make_pair("Eh", 3.14),
"foo", false,
some_pair);
In c++17 you may be able to workaround the problem and cheat compiler a bit by using template deduction of constructors:
#include <iostream>
#include <utility>
template <class... Args>
struct P:std::pair<Args...> {
P(Args... args):std::pair<Args...>(args...) { }
};
template <class... Args>
void foo(std::pair<const char *, Args>&&...) {
}
int main() {
foo(P{"abc", 1}, P{"abc", "abc"}, P{"abc", 2.0});
}
[live demo]

Caching function results including maybe void

I have a template whose template parameter represents a functional. That functional is called within the template, and the result of the functional should be stored, like this:
template <class F>
class C {
F f;
/* type see below */ cached;
// ... somewhere ...
cached = f();
};
I would like to retrieve the stored value later. Now, the template is supposed to work even if f returns void. Since I cannot generate variables of type void, the cached value should be of a void_placeholder_t type. Hence my class should look as follows:
template <class F>
class C {
F f;
result_after_void_replacement_t<F()> cached;
// ... somewhere ...
cached = invoke_and_replace_void (f);
};
Now I worked the whole afternoon on this problem and came up with the below solution. Honestly, I doubt that this problem is uncommon -- so isn't there a standard solution?
[Sorry, lengthy. Example given at the end.]
#include <iostream>
#include <typeinfo>
#include <functional>
struct void_placeholder_t {};
// dummy type, since we do not want to overload comma for void_placeholder_t
struct void_replacer { };
// overload comma to return either t oder void_replacer {}
// (uses that if first argument is void, overload is not called)
template <class T>
constexpr decltype(auto) operator , (T && t, void_replacer) {
return std::forward<T> (t);
}
//
// replace_void
// helper transforming a void_replacer into a void_placeholder_t
template <class T>
constexpr decltype(auto) replace_void (T && t) {
return std::forward<T> (t);
}
constexpr void_placeholder_t replace_void (void_replacer) {
return void_placeholder_t {};
}
//
// remove_rvalue_reference
//
template<class T> struct remove_rvalue_reference { using type = T; };
template<class T> struct remove_rvalue_reference<T &&> { using type = T; };
template <class T> using remove_rvalue_reference_t
= typename remove_rvalue_reference<T>::type;
//
// result_after_void_replacement, result_after_void_replacement_t
//
template <class S> struct result_after_void_replacement;
template <class F, class ... Args>
struct result_after_void_replacement <F (Args ...)> {
using type
= remove_rvalue_reference_t < decltype (
replace_void(
( std::declval<F> () (std::declval<Args> () ...),
void_replacer {} ) )
) >;
};
template <class S>
using result_after_void_replacement_t = typename
result_after_void_replacement<S>::type;
//
// invoke_and_replace_void
//
template <class F, class ... Args>
constexpr result_after_void_replacement_t<F && (Args &&...)>
invoke_and_replace_void (F && f, Args && ... args)
{
return replace_void(
( std::forward<F> (f) (std::forward<Args> (args) ...),
void_replacer {} ) );
}
// example
void f(double) { }
double g(double d) { return d + 11.0; }
int main() {
// conversion, without invoke_and_replace_void
auto xf = replace_void ( (f(42.0), void_replacer {}) );
std::cout << typeid(xf).name () << std::endl;
auto xg = replace_void ( (g(42.0), void_replacer {}) );
std::cout << typeid(xg).name () << " " << xg << std::endl;
// conversion, with invoke_and_replace_void and no type deduction
using F = void (double);
result_after_void_replacement_t<F& (double)> zf =
invoke_and_replace_void (f, 42.0);
std::cout << typeid(zf).name () << std::endl;
using G = double (double);
result_after_void_replacement_t<G& (double)> zg =
invoke_and_replace_void (g, 42.0);
std::cout << typeid(zg).name () << " " << zg << std::endl;
return 0;
}
There is no standard solution as in "something which is in the C++ standard". There was an attempt to support "Regular Void" which wasn't favored by the Evolution Working Group at the October 2015 meeting.
The usual approach is to deal with situations where function object may return void and the value would be processed using specialization. Especially when the function template in question is relatively complex and the common parts can't be factored easily, this approach is unfortunately rather annoying.
This should work for your case
template <class F, bool>
class C_helper{
public:
F f;
/* type see below */ cached;
// ... somewhere ...
cached = f();
};
template <class F>
class C_helper<F, true> {
public:
F f;
// ... somewhere ...
f();
};
template <class F>
class C: public C_helper<F, std::is_void<std::result_of<F()>>::value> {
};
This works fine:
template <typename Fn, typename RET, typename... Args >
struct Cache
{
Cache( Fn f ) : _fn(f) {}
const RET& operator()(Args ...args)
{
_cache = _fn( std::forward<Args>( args ) ... );
return _cache;
}
Fn _fn;
RET _cache;
};
template <typename Fn, typename... Args >
struct Cache< Fn, void, Args...>
{
Cache( Fn f ) : _fn(f) {}
void operator()(Args ...args)
{
_fn( std::forward<Args>( args ) ... );
}
Fn _fn;
};
template <typename Fn, typename... Args >
using C = Cache< Fn, typename std::result_of< Fn( Args... ) >::type, Args... >;
void f(double) { }
double g(double d) { return d + 11.0; }
C<decltype(&g), double> cache_g(g);
double res = cache_g( 1.0 );
C<decltype(&f), double> cache_f(f);
cache_f( 2.0 );