Calling a templated functor in a class template - c++

Is there any way to call the functor operator()( int ) of a the class template Foo as shown below (online version)
template<typename T>
struct Foo
{
template<typename U>
void operator()( int )
{
}
};
int main(int argc, char *argv[])
{
Foo<char> foo;
foo<bool>( 42 );
}
I'm getting the error message in gcc 4.9.3
error: expected primary-expression before ‘bool’
foo<bool>( 42 );
I'd prepend the functor with template if the member function wasn't a functor and was prefixed with ::, ., or ->. Without some help the compiler couldn't know how to parse this expression ; as a functor or an instantiation of an anonymous object of type foo<int>.

It would work with;
foo.operator()<bool>( 42 );
Operators play best with deduced template argument types.
You don't give enough detail of the context in which this is used, as alternatives you could consider;
making the call operator a member function and thus allow explicit template type arguments
a tag dispatch mechanism
accept the type U as an argument
For example;
template<typename U>
void operator()( int, U&& /*initial*/ )
{
// use the initial value of U
}
// called as...
foo(42, true); // U is bool in your example
Or simply the member function;
template<typename U>
void my_func( int )
{
}
// called as...
foo.my_fun<bool>( 42 );

Yes but it's ugly:
foo.operator()<bool>( 42 );

Unfortunately you'd need to use foo.operator()<bool>(42); for this. foo<bool> is valid for things like C++14 variable templates, not template call operators.
What you could do is tag the type and pass that in as an argument to the call operator to deduce the right type:
//tag
template <typename T>
struct type{};
template<typename T>
struct Foo
{
template<typename U>
//deduction on the tagged type
void operator()( type<U>, int )
{
}
};
int main(int argc, char *argv[])
{
Foo<char> foo;
foo( type<bool>{}, 42 );
// ^^^^^^^^^^^^ pass tag
}
You could make this a bit nicer using C++14 variable templates for the tag:
template <typename T>
struct type_t{};
//variable template for nicer usage
template <typename T>
type_t<T> type;
template<typename T>
struct Foo
{
template<typename U>
void operator()( type_t<U>, int )
{
}
};
int main(int argc, char *argv[])
{
Foo<char> foo;
foo( type<bool>, 42 );
//don't need {}^
}

Sadly the syntax gets more elaborate if the functor is itself a template. The below will fail:
template <typename Functor, typename ... Args>
void Foo (Functor & f)
{
f.operator()<Args...>();
}
struct MyFunctor
{
template <typename ...>
void operator () () {}
};
int main ()
{
MyFunctor f;
Foo(f);
}
We instead must write:
f.template operator()<Args...>();

Related

Error when using parameter pack with std::function [duplicate]

There are several questions on SO that relate to casting lambdas to std::functions, but I have yet to see one that uses a parameter pack for the argument list. This seems broken on my version of g++ (7.1.1-4), and possibly it's just not supported. So is this legal c++17 (by the standard)? If not, why?
#include <functional>
template <typename TReturn, typename ... TArgs>
void Functor(std::function<TReturn (TArgs...)> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int, int, int>(x);
return 0;
}
The code above won't compile because it fails type deduction. Obviously explicitly typing x as std::function<int (int, int)> instead of using auto makes the error go away. But that doesn't allow me to pass an r-value to Functor as I would like. I would also like to not loose any type-safety by using another template parameter for the function type.
What I really don't understand is why the above code fails to compile, but the below code is fine and works:
#include <functional>
template <typename TReturn, typename TArgA, typename TArgB>
void Functor(std::function<TReturn (TArgA, TArgB)> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int, int, int> (x);
return 0;
}
The issue is that the compiler doesn't know that you've intended int, int to be the whole of TArgs, and so tries to deduce the remainder of TArgs from the argument f.
For example, this would be valid:
Functor<int, int, int>(std::function<int(int, int, char, float)>{});
// TArgs := {int, int, [...] char, float}
So you need to instruct the compiler to not try to deduce the remainder of TArgs. For example, you could write:
(*Functor<int, int, int>)(x);
Or you could write Functor with a non-decomposed signature Sig:
template <Sig>
void Functor(std::function<Sig> f) {}
Or you could wrap the use of TArgs in the parameter f in a non-deduced context:
template <typename TReturn, typename ... TArgs>
void Functor(std::function<std::conditional_t<false, void, TReturn (TArgs...)>> f) {}
This fails:
#include <functional>
template <typename TReturn, typename ... TArgs>
void Functor(std::function<TReturn (TArgs...)> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int, int, int>(x);
return 0;
}
because you're not specifying that the entirety of TArgs... is {int, int}. What you are doing is specifying that the first two types are {int, int}. Effectively, by providing those three types, we've turned the deduction problem into:
template <typename ... TArgs>
void Functor(std::function<int(int, int, TArgs...)> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor(x);
return 0;
}
This doesn't compile because a lambda isn't a std::function (or derived from one), which is the same reason you couldn't have called this without having provided any types to begin with.
The non-variadic version doesn't have this problem, since you've provided all the types.
But really, what you want is:
template <typename F>
void Functor(F ) {}
This doesn't lose you any type safety. It's using std::function that loses type information, since that class template exists to type erase.
It is very rarely a good idea to cast a lambda to a std::function in a template if you are just going to call it. std::function is type-erasure, and templated type erasure only makes sense if you are going to "pass it on" somewhere else and/or return it.
In any case, try this:
template <class Sig>
void Functor(std::function<Sig> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int(int, int)>(x);
return 0;
}
but you should really just do
template <class F>
void Functor(F f) {}
which is perfectly type-safe.
If you want early type checking, you could write
template<class Sig, class F>
struct signature_compatible;
template<class R, class...Args, class F>
struct signature_compatible<R(Args...), F> :
std::is_consructible< R, std::result_of_t<F(Args...)>>
{};
then do
template <class Sig, class F>
void Functor(F f) {
static_assert( signature_compatible<Sig, F&>::value, "bad signature" );
}
but only if you really need to.
Here is a solution that will let you call functor without specifying it's template argument:
#include <functional>
#include <type_traits>
template <class T> struct Fun_trait {};
template <class T, class... Args, class Ret>
struct Fun_trait<auto (T::*) (Args...) const -> Ret>
{
using F = std::function<auto (Args...) -> Ret>;
};
template <class TReturn, class... TArgs>
void functor(std::function<TReturn (TArgs...)> f) {}
template <class F>
std::void_t<decltype(&F::operator())>
functor(F f)
{
return functor<typename Fun_trait<decltype(&F::operator())>::F>(f);
};
int main(int argc, char * argv[])
{
auto x = [] (int a, int b) { return a * b; };
// nice and easy:
functor(x);
return 0;
}
This is just a lazy first draft to get you started. You need to expand it to support forwarding and non-const operator().
It works in 2 stages:
1st we have Fun_trait who - for pointer method types (e.g. the operator() of a lambda) - has defined an alias F for the required std::function argument type.
Next we have a overload of your function functor which via SFINAE with std::void_t kicks in only for functors with a non-overloaded operator() (e.g. a lambda) and then using the above trait calls the main function functor with the correct template argument deduced.

How to write a template that can deduce a type use a function's argument type?

How to write a template that use function as template parameter, and auto deduce other typename by this function's argument type?
void foo(int *p) {}
template<typename T, void (*F)(T*)>
struct bar
{
bar(T* t)
{
F(t);
}
}
int *p;
bar<int, foo> b(p); // both int and foo are required here
how to write a template that supports to use only foo as argument
bar<foo> b(p);
If you can use c++17 with it's auto template parameter (like #n.m. said in the comments) you can use it as the template parameter and then the type T with type traits.
First off we need the standard type traits and also a type trait to get the argument to a unary function (your foo) that we can write like this:
#include <type_traits>
// Trait to get the argument type of a unary function
template<typename T>
struct unary_func_arg;
template<typename R, typename T>
struct unary_func_arg< R(*)(T) >
{
using type = T;
};
This will produce an error if you put anything other than a function pointer into it since the main specialization is not declared.
After this we can finally write bar as this:
template< auto F >
struct bar
{
// Assert it's a function pointer
static_assert( std::is_pointer_v<decltype(F)> );
static_assert( std::is_function_v< std::remove_pointer_t<decltype(F)> > );
// Get the parameter type
using T = typename unary_func_arg< decltype(F) >::type;
bar(T t)
{
F(t);
}
};
We have to make sure that F is a function pointer so we static assert that, then we get the type T from our type trait.
Now you can declare f and b like this:
int* p;
bar<foo> b(p);
EDIT: If you need T to be not a pointer so you can write T*, you can either make a type trait that removes 1 pointer level or modify the type trait here to as such:
// Trait to get the argument type of a unary function
template<typename T>
struct unary_func_arg_pointer;
template<typename R, typename T>
struct unary_func_arg_pointer< R(*)(T*) >
{
using type = T;
};
Now T will be just int in this example
In C++11 classes cannot deduce all the types of a passed function. But a function can.
So this function can be written:
template<typename Ret, typename Param>
Deduced_Types<Ret, Param> deduce_type(Ret (*)(Param))
{
return Deduced_Types<Ret, Param>();
}
This function uses a type to store the deduced types (it has to be declared before the function):
template<typename Ret, typename Param>
class Deduced_Types
{
public:
typedef Ret Return_type;
typedef Param Parameter_type;
};
Now to test it;
int f(bool)
{
return 0;
}
int main(int argc, char* argv[])
{
decltype( deduce_type(f) )::Return_type i = 0;
return i;
}
It works.
So Now to Bar:
template< class F >
class Bar
{
public:
typedef typename F::Return_type Func_Return_type;
typedef typename F::Parameter_type Fun_Param_type;
};
which has to be called:
Bar< decltype(deduce_type(f)) > b;
(this is where You can use a macro)
Works on gcc 4.8.1 : https://godbolt.org/z/1cz2pk
Edit:
Pre C++17 function could not be passed into a template.
So what is needed is that you need to pass the function pointer into the class. And a static_assert to verify the parameters are correct:
#include <type_traits>
struct bar
{
template<typename F, typename T>
bar(F f, T t)
{
typedef decltype(deduce_type(f)) D;
static_assert(std::is_same<typename D::Parameter_type, T>::value,"parameter has different type function parameter");
f(t);
}
};
Now instead of passing the function as a template parameter, the function pointer is passed in as a parameter:
void foo(int *p) {}
int *p;
bar b(foo, p);
Only problem here is that the class has to store this pointer for future use.
In C++17, you might do
template <auto> struct bar;
template<typename T, void (*F)(T*)>
struct bar<F>
{
bar(T* t) { F(t); }
};
with usage:
int* p = nullptr;
bar<foo> b(p);
Prior C++17, you might do:
template <typename T, T> struct bar;
template<typename T, void (*F)(T*)>
struct bar<void (*)(T*), F>
{
bar(T* t) { F(t); }
};
With usage:
int* p = nullptr;
bar<decltype(&foo), &foo> b(p);
MACRO can be used to remove duplication such as:
#define BAR(Func) bar<decltype(&Func), &Func>
#define TYPE_AND_VALUE(V) decltype(V), V>
to allow:
BAR(foo) b(p);
bar<TYPE_AND_VALUE(&foo)> b(p);

Can class type be deduced from pointer to member function template parameter

Is it possible to deduce the type of the class T from its pointer to memmber T::*f as shown below.
struct Foo
{
void func(){}
};
template<typename T, void (T::*f)()>
void bar()
{
}
int main()
{
bar<Foo,Foo::func>();
// bar<Foo::func>(); // Desired
}
In C++11/14 I would say no, unless you accept to deduce it by passing the pointer as a function argument:
template<typename T>
void bar(void(T::*f)())
{
}
int main()
{
bar(&Foo::func);
}
In C++17 you can have a single parameter function template as shown by #Jarod42, but you don't have the type T deduced anyway (if it was the purpose, as it seems to be from the question).
If you have access to C++17, you can use auto template parameter and decltype to inspect the class type:
struct Foo { void func(){} };
template<typename R, typename C, typename... Args>
C function_pointer_class(R (C::*)(Args...));
template<auto f>
std::enable_if_t<std::is_member_function_pointer_v<decltype(f)>>
bar() {
using class_t = decltype(function_pointer_class(f));
// stuff...
}
int main() {
bar<&Foo::func>();
}
In C++17, you will be allowed to write
template<auto M>
void bar();
Which allows
bar<&Foo::func>();

Can outer parameter pack be expanded with inner parameter pack to be deduced?

Given overloaded functions f1:
void f1(int);
int f1(char);
And a class template X with member template f:
template<class T>
struct X
{
template<class U>
static void f(T(*p)(U));
};
The compiler is able to resolve f1 from part of the function type:
X<int>::f(f1); // T = int (specified), U = char (deduced)
X<void>::f(f1); // T = void (specified), U = int (deduced)
However, a variadic class template Y with parameter pack at both sides:
template<class... T>
struct Y
{
template<class... U>
static void f(T(*...p)(U));
};
Fail to do the same thing:
Y<int>::f(f1); // error
Y<void>::f(f1); // error
Y<int, void>::f(f1, f1); // error
Note that it's OK if the parameter pack is only at one side:
template<class... T>
struct Z1
{
template<class U>
static void f(T(*...p)(U));
};
template<class T>
struct Z2
{
template<class... U>
static void f(T(*...p)(U));
};
Z1<int>::f(f1); // ok
Z2<void>::f(f1); // ok
This showns a problem: the outer parameter pack T cannot be expanded while the inner parameter pack U is still dependant.
I imagine the compiler could expand Y::f to something like below when Y<int, void> is instantiated:
template<class... U>
void f(int(*p0)(U0), void(*p1)(U1));
where U0 and U1 denote the first 2 elements of parameter pack U.
But it seems that compilers(g++/clang) refuse to do so and leave the whole p unexpended.
where in the standard does it specify such a behavior? Could it be a standard defect or something to improve?
I've extracted another code snippet that works, although still doesn't satisfies your needs, but may lead you to something:
void f1(int)
{
}
int f1(char)
{
return 0;
}
template <class Out, class In>
struct UniFunction
{
typedef Out fn(In);
typedef fn* ptr;
};
template<class... T>
struct Y
{
//template<class... U>
//static void f(T(*...p)(U)...);
template <class... U>
struct YY
{
static void f(typename UniFunction<T, U>::ptr...)
{
}
};
};
int main( int argc, char** argv )
{
Y<int>::YY<char>::f(f1);
return 0;
}
This UniFunction is just for clarity and maybe show that the double parallel expansion of parameter pack isn't impossible, there's just a small problem.
I think you can still enforce argument type deduction if you provide additionally a "template function" (structure template with typedefs) that will extract (using type_traits or something) the argument type and return type from the function pointer. By having that, you should be able to provide the Y::f function with just one template parameter (kinda X...), extract the argument type from that X being a function pointer, then pass it explicitly to YY template, as shown here.

Function template taking a template non-type template parameter

How does one take a templated pointer to a member function?
By templated I mean that the following types are not known in advance:
template param T is class of the pointer to member
template param R is the return type
variadic template param Args... are the parameters
Non-working code to illustrate the issue:
template <???>
void pmf_tparam() {}
// this works, but it's a function parameter, not a template parameter
template <class T, typename R, typename... Args>
void pmf_param(R (T::*pmf)(Args...)) {}
struct A {
void f(int) {}
};
int main() {
pmf_tparam<&A::f>(); // What I'm looking for
pmf_param(&A::f); // This works but that's not what I'm looking for
return 0;
}
Is it possible to achieve the desired behavior in C++11?
I don't think this notation is possible, yet. There is proposal P0127R1 to make this notation possible. The template would be declared something like this:
template <auto P> void pmf_tparam();
// ...
pmf_tparam<&S::member>();
pmf_tparam<&f>();
The proposal to add auto for non-type type parameters was voted into the C++ working paper in Oulu and the result was voted to become the CD leading towards C++17 also in Oulu. Without the auto type for the non-type parameter, you'd need to provide the type of the pointer:
template <typename T, T P> void pmf_tparam();
// ...
pmf_tparam<decltype(&S::member), &S::member>();
pmf_tparam<decltype(&f), &f>();
As you've not said really what you are after in the function, the simplest is:
struct A {
void bar() {
}
};
template <typename T>
void foo() {
// Here T is void (A::*)()
}
int main(void) {
foo<decltype(&A::bar)>();
}
However if you want the signature broken down, I'm not sure there is a way to resolve the types directly, however you can with a little indirection...
struct A {
void bar() {
std::cout << "Call A" << std::endl;
}
};
template <typename R, typename C, typename... Args>
struct composer {
using return_type = R;
using class_type = C;
using args_seq = std::tuple<Args...>;
using pf = R (C::*)(Args...);
};
template <typename C, typename C::pf M>
struct foo {
static_assert(std::is_same<C, composer<void, A>>::value, "not fp");
typename C::return_type call(typename C::class_type& inst) {
return (inst.*M)();
}
template <typename... Args>
typename C::return_type call(typename C::class_type& inst, Args&&... args) {
return (inst.*M)(std::forward<Args...>(args...));
}
};
template <class T, typename R, typename... Args>
constexpr auto compute(R (T::*pmf)(Args...)) {
return composer<R, T, Args...>{};
}
int main() {
foo<decltype(compute(&A::bar)), &A::bar> f;
A a;
f.call(a);
}
The above should do what you are after...
What you can do is
template <template T, T value>
void pmf_tparam() {}
and then
pmf_tparam<decltype(&A::f), &A::f>();
The problem is not knowing the type of the argument and wanting a template argument of that type.
With an additional decltype (still in the templated parameter), this works:
#include <iostream>
using namespace std;
template <typename T, T ptr>
void foo (){
ptr();
}
void noop() {
cout << "Hello" << endl;
}
int main() {
//Here have to use decltype first
foo<decltype(&noop), noop>();
return 0;
}