I have a template class, with an internal method that is itself templated.
Consider the following minimal working example
#include <functional>
template<typename T>
class P{
public:
template <typename U>
P<U> call(std::function< P<U> (T)> f){
return f(return_value);
}
T return_value;
};
P<int> foo() {
P<int> value = P<int>();
return value;
}
P<float> bar(int arg) {
return P<float>();
}
int main()
{
auto res = foo().call<float>(bar);
return 0;
}
As you can see in the main function, the compiler forces me to to specify the float type for calling the call() function, eventhough the type should be obvious from passing over the bar() function, that specifies the float type.
Is it somehow possible to deduct the type so that the code in the main function can be simplified to the following statement:
auto res = foo().call(bar);
std::function is not the type that you should use whenever you want to pass a function around. std::function is a type that uses type erasure to be able to store different types of callables in one type. If you don't need that then you need no std::function:
#include <functional>
template<typename T>
class P{
public:
template <typename F>
auto call(F f){
return f(return_value);
}
T return_value{}; // don't forget to initialize !
};
P<int> foo() {
P<int> value = P<int>();
return value;
}
P<float> bar(int arg) {
return P<float>();
}
int main()
{
auto res = foo().call(bar);
return 0;
}
Using partial specializatzion you can get the return type of bar and you can get the float from P<float>:
#include <type_traits>
#include <iostream>
template <typename T> class P;
// get return type from function
template <typename T> struct return_type;
template <typename R,typename...args>
struct return_type<R(args...)> { using type = R; };
// get T from P<T>
template <typename P> struct P_arg;
template <typename T> struct P_arg< P<T> > { using type = T; };
// combine both
template <typename F>
struct get {
using type = typename P_arg<typename return_type<F>::type >::type;
};
template<typename T>
class P{
public:
template <typename F>
auto call(F f){
return f(return_value);
}
T return_value{};
};
P<float> bar(int arg) {
return P<float>();
}
int main()
{
std::cout << std::is_same_v< get<decltype(bar)>::type,float>;
return 0;
}
Though that does not really help here, because you cannot use it to decalre the return type of P::call, as it requires P<float> to be already complete.
I have the following code:
#include <iostream>
using namespace std;
template <class T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
function(get_num, 3);
return 0;
}
I need to call the get_num() function with an int argument. But compiler gets this error:
prog.cpp: In function ‘int main()’: prog.cpp:21:21: error: no matching
function for call to ‘function(<unresolved overloaded function type>,
int)’ function(get_num, 3);
^ prog.cpp:15:6: note: candidate: template<class T1, class T2> void function(T1 (*)(T2), T2) void function(T1
(*callback)(T2), T2 arg) {
^~~~~~~~ prog.cpp:15:6: note: template argument deduction/substitution failed: prog.cpp:21:21: note: couldn't deduce
template parameter ‘T1’ function(get_num, 3);
How can it be done ?
After removing template <class T> from int get_num(int) to get a normal overload set, you can use Some programmer dude’s answer.
In this answer I want to elaborate how you can still use a function pointer based parameter.
If you switch the arguments to function at least gcc is able to deduce it:
template <typename T, typename U>
void function2(T arg, U(*callback)(T)) {
callback(arg);
}
clang doesn’t like it when you use U there, so if your return types will always be the same as your arguments, you can use T twice:
template <typename T>
void function2(T arg, T(*callback)(T)) {
callback(arg);
}
To resolve disambiguities like the one in your error message in general, you can also do the overload resolution manually with static_cast:
function(static_cast<float(*)(float)>(&get_num), 3.0f);
function(static_cast<int(*)(int)>(&get_num), 3);
One problem is that you have different types for return-type and argument-type for function, but in reality both are the same.
That means you could do something like
template<typename T, typename F = T(T)>
void function(F callback, T arg)
{
callback(arg);
}
The template argument F is just to simplify the callback argument declaration.
You have a template <class T> in front of your int get_num(int k). Lets assume for a moment it isnt there, then this works:
Sometimes you cannot change the function into a template, but need to work with function pointers to a function that has several overloads. The way to choose the right overload is to specify the type of the function pointer (because for different overloads the function pointers are of different type).
typedef int (* int_get_num_t)(int);
int main() {
int_get_num_t correct_overload = get_num;
function(correct_overload, 3);
return 0;
}
In case the int get_num(int k) is really supposed to be a template (then why the float one isnt?) then you simply have to pick the template version:
int_get_num_t correct_overload = get_num<int>;
where actually you could pass any type instead of int as your template get_num always takes an int and returns an int irrespective of the template parameter.
And finally... you actually dont need the second overload for get_num but you need only one template. And in that case you still need to pick the right template to get the function pointer:
template <typename T>
T get_num(T k) { return k + 3; }
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
int_get_num_t correct_overload = get_num<int>;
function(correct_overload, 3);
return 0;
}
Here's the one using the C++ functors.
#include <iostream>
using namespace std;
template<class T>
struct get_num : public std::unary_function<T,T>
{
T operator()(const T& k) {
return k+3;
}
};
template< class T1, class T2 >
void function( T1 fun, T2 arg)
{
fun(arg);
cout << fun(arg) << endl;
}
int main()
{
function(get_num<int>(), 3);
return 0;
}
The following code will work:
#include <iostream>
using namespace std;
template<typename T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template<typename T1, typename T2> // Maybe here you want the `typename`, not the `class`
void f(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
f(get_num<int>, 3); // The key point is here!
return 0;
}
The reason you get the compiling error is the compiler could not deduce the type T if you just use get_num, because all the arguments are nothing with the type T.
You have to specify the type of function
#include <iostream>
#include <string>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
std::string get_num (double a)
{
return "this is a string " + std::to_string(a);
}
template <class T1, class T2>
using callback = T1(*)(T2);
template <class T1, class T2>
void function(callback<T1, T2> function, T2 arg) {
std:: cout << function(arg) << std::endl;
}
int main() {
// your code goes here
function<int, int>(get_num, 3);
function<std::string, double>(get_num, 3);
system("pause");
return 0;
}
Why 2 different template arguments? -The OP's question is not about optimization, it is about
How to pass the specific callback to a template function?
So, this is one of many implementations, solving the specific error.
I allowed myself to simplify a bit Your code. This should work fine:
#include <iostream>
using namespace std;
template <class T>
T get_num(T k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 callback, T2 arg) {
callback(arg);
}
int main() {
function(get_num<int>, 3);
return 0;
}
I want to provide an solution which differs a bit.
I explain it inside the code to make it hopefully more comfortable to read and understand:
// create a helper class,
// which collects all callable classes to build one callable object later
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
// instead of free functions, build objects with methods
// and use operator() instead of function names.
// this makes it easier to "understand" that this will be an callable object
struct Func1
{
int operator()(int k) {
return k + 3;
}
};
struct Func2
{
float operator()(float k) {
return k + 3;
}
};
// adapt your code to this:
template <class T1, class T2>
auto function(T1 callback, T2 arg) {
return callback(arg);
}
// and finaly you can use it this way, also with return types
// the central hack is:
// funcs{ Func1(), Func2() }
// this will generate a callable object with all the overloads
// from the inserted callable objects
int main() {
// your code goes here
std::cout << function(funcs{ Func1(), Func2() }, 3) << std::endl;
std::cout << function(funcs{ Func1(), Func2() }, (float)7.999) << std::endl;
return 0;
}
I want to write a variadic template or const expressions which 1) execute a template functor N times and 2) accumulates the result. I wrote a small example which actually fails compilation as soon as I move the function which gets executed into a template functor. I have the feel I am close to the solution, but maybe I am wrong.
#include <iostream>
#include <string>
struct F {
template <int id>
static int run(int val) {
return id * val;
}
};
template<unsigned int n>
struct accumulate_for
{
template <class Funct>
static int get(int val) {
return
(
accumulate_for<n-1>::get(val)
+
Funct::run<n>(val)
);
}
};
template<>
struct accumulate_for<0>
{
template <class Funct>
static int get(int val) {
return 0;
}
};
int main()
{
std::cout << accumulate_for<3>::get<F>(1) << std::endl;
}
accumulate_for<n>::get is a member function template, so you have to specify template argument when calling it.
You need to use template keyword to indicate that get and run (which are both dependent names) are templates.
e.g.
template<unsigned int n>
struct accumulate_for
{
template <class Funct>
static int get(int val) {
return
(
accumulate_for<n-1>::template get<Funct>(val)
// ~~~~~~~~ ~~~~~~~
+
Funct::template run<n>(val)
// ~~~~~~~~
);
}
};
LIVE
For more info about the usage of the template keyword, refer to Where and why do I have to put the “template” and “typename” keywords?
Suppose I have a template function:
template<typename T>
T produce_5_function() { return T(5); }
How can I pass this entire template to another template?
If produce_5_function was a functor, there would be no problem:
template<typename T>
struct produce_5_functor {
T operator()() const { return T(5); }
};
template<template<typename T>class F>
struct client_template {
int operator()() const { return F<int>()(); }
};
int five = client_template< produce_5_functor >()();
but I want to be able to do this with a raw function template:
template<??? F>
struct client_template {
int operator()() const { return F<int>(); }
};
int five = client_template< produce_5_function >()();
I suspect the answer is "you cannot do this".
I suspect the answer is "you cannot do this".
Yes, that is the case, you cannot pass a function template as a template argument. From 14.3.3:
A template-argument for a template template-parameter shall be the
name of a class template or an alias template, expressed as
id-expression.
The template function needs to be instantiated before you pass it to the other template. One possible solution is to pass a class type that holds a static produce_5_function like so:
template<typename T>
struct Workaround {
static T produce_5_functor() { return T(5); }
};
template<template<typename>class F>
struct client_template {
int operator()() const { return F<int>::produce_5_functor(); }
};
int five = client_template<Workaround>()();
Using alias templates, I could get a little closer:
template <typename T>
T produce_5_functor() { return T(5); }
template <typename R>
using prod_func = R();
template<template<typename>class F>
struct client_template {
int operator()(F<int> f) const { return f(); }
};
int five = client_template<prod_func>()(produce_5_functor);
How about wrapping that function?
template<typename T>
struct produce_5_function_wrapper {
T operator()() const { return produce_5_function<T>(); }
};
Then you can use the wrapper instead of the function:
int five = client_template< produce_5_function_wrapper >()();
Using the template function alone will not work, there's no such thing as "template template functions".
I would like to have a general templated function declaration for which I do not know (already) the return type, similar to:
**template <class T> auto getIds() noexcept -> std::vector<Any>;**
The function could then be specialized with several input types, and a return type based on it:
template <> auto getIds<MyClass>() noexcept -> std::vector<decltype(MyClass::id)>
{
// implementation here.
}
And finally call it without to set the return:
auto val = getIds<MyClass>();
Is that possible? How?
Notes:
What I want to avoid is to have to set manually the Id type in the call function:
auto val = getIds<MyClass, decltype(MyClass::id)>(); // Ugly
I also discard any (non based on template) solution like extending all types from a RootMyClass. Is not that these solutions are bad, but they miss the point of this question.
Trying to be a bit clearer:
If I wrote
class MyClass { public: int id1=4;};
template <class T, class Id> auto getIds() -> Id;
template <> auto getIds<MyClass, decltype(MyClass::id1)>() -> decltype(MyClass::id1)
{
return 1;
}
auto main() -> int
{
getIds<MyClass>(); // Do not compile
getIds<MyClass, decltype(MyClass::id1)>(); // Compile but ugly
}
I would like the return type to be implicit, but I did not found a way to achieve that with specializations:
template <class T> getIds() noexcept -> WHICH TYPE?;
You cannot change the return type in a specialization, unfortunately. What you can do is change the return type in different overloads. Obviously. Furthermore, function template specializations are much more complicated than function overloads anyway, so let's do that.
Introduce an empty type wrapper, say:
template <typename T> struct wrapper { };
And forward the default implementation to that (I'm assuming C++14 here, otherwise you could wrap that in decltype() with a trailing return):
template <typename T>
auto getIds() { return getIds(wrapper<T>{}); }
Declare the generic version as:
template <typename T>
void getIds(wrapper<T> );
Don't define it. Then, anytime somebody tries to do:
auto ids = getIds<X>();
If there is no overload, that will simply fail to compile as you cannot assign from void. Then, you can overload as you see fit:
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{ ... }
FINAL EXAMPLE:
#include <iostream>
#include <vector>
template <typename T> struct wrapper { };
template <typename T>
auto getIds() -> decltype(getIds(wrapper<T>{}))
{
return getIds(wrapper<T>{});
}
template <typename T>
void getIds(wrapper<T> ) { }
struct MyClass {
int id;
};
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{
return {1, 2, 3};
}
int main()
{
for (auto id : getIds<MyClass>()) {
std::cout << id << " ";
}
}
This is actually very similar to Haskell typeclasses, and, surprisingly, works. For real usage I would use functors to allow partial specializations, though.
#include <iostream>
template<typename T>
decltype(T::x) getX(T const& t) { return; }
class A { public: int x; A(int x):x(x){} };
template<> int getX<A>(A const& a) {
return a.x;
}
class B { public: std::string x; B(std::string x):x(std::move(x)){} };
template<> std::string getX<B>(B const& b) {
return b.x;
}
int main() {
A a(42);
B b("43");
std::cout << getX(a) << std::endl;
std::cout << getX(b) << std::endl;
}
As you can see, each specialization has to (can?) provide the return type explicitly. decltype(A::x) (and B::x), respectively) could be used instead if you so prefer.
To make it even more Haskell-ish, you could expect a type tag in the type itself (basically a type family):
template<typename T>
typename T::TypeOfX getX(T const& t) { return; }
And consequently:
class A {
using TypeOfX = int;
TypeOfX someComplexLogicToGetX();
};
Both solutions to the type being instantiated for the actual type, except one gets it from a type of a field, and the other from a direct "type variable".