The following works
#include <iostream>
template<typename A, typename B> double func1(B x, B y)
{
A a = 3.0f;
return a x y;
}
template<typename A, typename B> double func2()
{
B x = 5.0;
B y = 8.0;
return func1<float>(x, y);
}
int main()
{
std::cout << func2<float, double>() << "\n";
}
However, what if I would like func1
to be substituted with another similar function? One with the same number and type of arguments and template parameters. I tried template<template<...
like below, and it didn't seem to work.
#include <iostream>
template<typename A, typename B> double func1(B x, B y)
{
A a = 3.0f;
return a x y;
}
template<template <typename, typename> typename func, class A, class B>
double func2()
{
B x = 5.0;
B y = 8.0;
return func<A, B>(x, y);
}
int main()
{
std::cout << func2<func1, float, double>() << "\n";
}
It would be nice if a pattern like the one above worked.
Even better if func
, could be partially templatized and still deduce from the type of the arguments like
#include <iostream>
template<typename A, typename B> double func1(B x, B y)
{
A a = 3.0f;
return a x y;
}
template<template <typename, typename> typename func, class A, class B>
double func2()
{
B x = 5.0;
B y = 8.0;
return func<A>(x, y);
}
int main()
{
std::cout << func2<func1, float, double>() << "\n";
}
Any ideas on how to get the 2nd snippet to work?
Could you do so with template deduction as well? Could c 20 concepts do magic here?
CodePudding user response:
Function templates have some restrictions that class templates do not have. Consider that the type of func1<A,B>
alone does not help you. You'd need the concrete function to call it. With a class template on the other hand, the type (an instantiation of the template) is all you need to know to use it.
Your 2nd code snippet works if you only change func1
to be a functor, a class with operator()
:
#include <iostream>
template<typename A, typename B>
struct func1 {
double operator()(B x, B y){
A a = 3.0f;
return a x y;
}
};
template<template <typename, typename> typename func, class A, class B>
double func2(){
B x = 5.0;
B y = 8.0;
return func<A,B>{}(x,y);
}
int main(){
std::cout << func2<func1, float,double>() << "\n";
}
To deduce B
from the parameters you can make operator()
a template:
#include <iostream>
template <typename A>
struct func1 {
template<typename B>
double operator()(B x, B y){
A a = 3.0f;
return a x y;
}
};
template<template <typename> typename func, class A, class B>
double func2(){
B x = 5.0;
B y = 8.0;
return func<A>{}(x,y);
}
int main(){
std::cout << func2<func1, float,double>() << "\n";
}
CodePudding user response:
Alternative to the templated functors given in the other answers, one can also use a generic lambda, along with the lambda's template support from c 20.
// generic lambda
const auto func1 = [](auto x,auto y)
{
decltype(x) a = 3.0f;
return static_cast<double>(a x y);
};
template<typename Func, class A, class B>
double func2() {
B x = 5.0;
B y = 8.0;
return Func{}.template operator()<A> (x, y);
// ^^^^^^^^^^^^^^^^^call of lambda like templated lambda!
}
This required the calling to be like:
std::cout << func2<decltype(func1), float, double>() << "\n";
// ^^^^^^^^^^^^^^^^^^^passing type of the lambda
CodePudding user response:
Even better if func, could be partially templatized and still deduce from the type of the arguments like
You can turn func1
into an functor with a template operator()
, and partially specify the template parameter through .template operator()<A>
.
#include <iostream>
struct Fun1 {
template<typename A, typename B>
double operator()(B x, B y){
A a = 3.0f;
return a x y;
}
};
template<typename Func, class A, class B>
double func2(){
B x = 5.0;
B y = 8.0;
return Func{}.template operator()<A>(x, y);
}
int main(){
std::cout << func2<Fun1, float, double>() << "\n";
}