Type testing with templates C++ - c++

So I have a function that takes two possible argument types, each of which is a lambda function type I have predefined. The two possibilities are CellFType and FType. The function is nearly identical for both cases, but at one line I need it to do two different things depending on the FunctionType. I want to avoid having a whole extra overload for this so I have templated it as such
/// Returns the integral 2 norm of a function
template <typename FunctionType>
double norm(const FunctionType &f)
{
double value = 0.0;
for (size_t iT = 0; iT < n_cells; iT++)
{
QuadratureRule quadT = cell_quads[iT];
for (size_t iqn = 0; iqn < quadT.size(); iqn++)
{
double qr_weight = quadT[iqn].w;
VectorRd f_on_qr = (typeid(FunctionType) == typeid(FType<VectorRd>) ?
f(quadT[iqn].vector()) : f(quadT[iqn].vector(), cells[iT])); // *ERROR*
value += qr_weight * scalar_product(f_on_qr, f_on_qr);
}
}
return sqrt(value);
}
FType and CellFType are also both templated as such:
template <typename T>
using CellFType = std::function<T(const VectorRd &, const Cell *)>;
template <typename T>
using FType = std::function<T(const VectorRd &)>;
Why is this causing issues? How can I type test properly here?

The solution in the comments, to call an overloaded function, is of course the most straightforward to understand and therefore best approach.
But, sometimes it's nice to keep it all inlined. Since you're using C++17, there's this helper class that gets used a lot with std::visit:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
It takes a bunch of lambdas, and converts them into a class with a call operator overload to invoke each lambda. You can use this to dispatch your case as well:
VectorRd f_on_qr = overloaded {
[&](FType<VectorRd> g) { return g(quadT[iqn].vector()); },
[&](CellFType<VectorRd> g) { return g(quadT[iqn].vector(), cells[iT])); }
} (f);
Proof of concept:
https://godbolt.org/z/G5qWGK

Related

How to pass std::sqrt as an argument

Im trying to create a generic function Foo that will accept an argument and Op what will be applied to it.
template <template<class> class Op>
float foo(float boo) {
return Op(boo);
}
template <template<class> class Op>
float foo(float a, float b) {
return Op(a, b);
}
void caller() {
float boo = 2.3;
auto res1 = foo<std::plus>(boo, boo); // works
auto res2 = foo<std::sqrt>(boo); // fail. error: no instance of overloaded function.
auto res3 = foo<std::exp>(boo); // fail. error: no instance of overloaded function
}
I think its related that std::sqrt is
"A set of overloads or a function template accepting an argument of
any integral type. "
while std::plus is
Function object for performing addition.
Can someone, please, help fix this? How do i pass std::sqrt and std::exp to foo?
As you've identified, the problem is that your template expects a type (because that's how you've written it), and though std::plus is a type (a functor), std::sqrt is a function.
It's hard to give a concrete solution for your problem, because you never showed your usage of Op.
But, generally, this is easy to do with an auto template parameter:
template <auto Op>
float foo(const float boo) {
return Op(boo);
}
If your version of C++ is too old, you'll need to add a version that takes a function pointer instead.
std::sqrt is an overloaded function, not a type. A simple fix would be to write a generic lambda that wraps std::sqrt, and then use its type when calling foo, like this:
auto sqrt = [](auto n) { return std::sqrt(n); };
auto res2 = foo<decltype(sqrt)>(boo); // ok
And you can do the same for std::exp.
Whether this is a good fix depends on how you want to use the Op parameter, which is not clear from the question.
You can't pass an overload set as a template argument. A simple workaround could be to wrap sqrt and exp into functors with a templated operator():
struct Sqrt {
template<class T>
T operator()(T t) const { return std::sqrt(t); }
};
struct Exp {
template<class T>
T operator()(T t) const { return std::exp(t); }
};
Then the following will work
auto res2 = foo<Sqrt>(boo);
auto res3 = foo<Exp>(boo);

Handling refactorings, template SFINAE tests and lambdas

The following (academically built, non working) code has two "problems" that I know how to solve in an ugly way. I would like a pretty one.
#include <type_traits>
template<class T> struct Integer {
Integer(T t) { static_assert(std::is_integral_v<T>, "Must be int"); }
};
template<class T> struct Floating {
Floating(T t) { static_assert(std::is_floating_point_v<T>, "Must be flating point"); }
};
template<class T> void brol(T t)
{
Integer i(t); //these two cannot work together
Floating f(t);
template<class U> auto stuff = [] (U& u) -> void //invalid syntax : no template on bloc scope
{ u *= 2; }
if(std::is_integral_v<T>)
stuff(i);
else
stuff(f);
}
int main()
{
brol(2);
brol(2.0);
}
Obviously, I cannot build an Integer and a Floating inside if the function brol(), because of the static_asserts. This problem can be easily solved with SFINAE tests, either nicely with std::enable_if_v or with some ... -> decltype( ... ) trickery. In the same way, I can also improve the end of the function body and avoid the if/else block
The lambda stuff() cannot be template (because the compiler states it cannot). I * could * make it independent and hide it in a subnamespace, but it's not so great.
HOWEVER, I cannot simply make an SFINAE test with std::enable_if, as the prototypes will only differ with their default template arguments and this is illegal (cf. documentation, section Notes in std::enable_if).
On the other hand, I don't know how to solve ussie 2 nicely...
It seems to me that std::conditional should solve all your problems
template <typename T>
void brol (T t)
{
using U = std::conditional_t<std::is_integral_v<T>, Integer<T>, Floating<T>>;
U u{t};
auto stuff = [] (U & u) -> void { u *= 2; };
stuff(u);
}
Anyway, the problem with the lambda could be solved also with a generic lambda (as pointed by rustyx)
auto stuff = [] (auto & u) -> void { u *= 2; };
Regarding the final if, in C++17 (you're using std::is_integral_v, so you're using C++17) you can also use if constexpr in similar circustances
if constexpr (std::is_integral_v<T>)
stuff(i);
else
stuff(f);
but remain the problem that you have to define i or f.
It's unclear what the purpose of your Integer and Floating is...
But regarding the "template<class U> auto stuff = [](U& u)" part, C++14 does make the lambda a template automatically if you simply use auto as the parameter type:
template<class T> void brol(T t) {
auto stuff = [](auto& u)
{ u *= 2; };
stuff(t);
}
int main() {
brol(2);
brol(2.0);
}

C++ Convert tuple of homogeneous wrapped type to tuple of raw type

I'd like to call std::apply() to a function; however, I am unable to because the std::tuple I use is currently wrapped. For example:
#include <tuple>
template <class T>
struct wrapped
{
wrapped(T t) : t(t) {}
T t;
};
template <class T, class ... Args>
struct delay_call
{
T(*callback)(Args...);
std::tuple<Args...> params;
delay_call(T(*callback)(Args...), Args ... params) :
callback(callback), params(params...)
{}
T call()
{
return std::apply(callback, params);
}
};
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
std::tuple<Args...> params; // = w_params.t
return std::apply(callback, actual_params);
}
};
float saxpy(float a, float x, float y)
{
return a * x + y;
}
int main()
{
float a = 1, x = 2, y = 3;
delay_call delay_saxpy(saxpy, a, x, y);
wrapped w_a = 1.f, w_x = 2.f, w_y = 3.f;
delay_call_with_wrap w_delay_saxpy(saxpy, w_a, w_x, w_y);
float result = delay_saxpy.call();
float w_result = w_delay_saxpy.call();
}
the delay_call struct works as expected; however, I am unsure how to go about extracting the actual value of each tuple element and giving that to std::apply() to execute.
In short, for delay_call_with_wrap::call, how would I convert std::tuple<wrapped<Args>...> to a std::tuple<Args...>?
I would avoid std::apply completely and call the callback directly by unpacking the tuple using std::index_sequence:
template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
return callback(std::get<I>(w_params).t...);
}
T call()
{
return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
In short, for delay_call_with_wrap::call, how would I convert std::tuple<wrapped<Args>...> to a std::tuple<Args...>?
It seems to me is better avoid std::apply() using the old std::make_index_sequence/std::index_sequence way (see HolyBlackCat answer).
But, if you really want to use std::apply(), you can call it a first time to unwrap the tuple (to get a tuple of unwrapped values) and then call is as usual.
I mean something as
T call ()
{
auto actual_params = std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params);
return std::apply(callback, actual_params);
}
or, in a single call, directly
T call()
{
return std::apply(callback,
std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params));
}
This solution is reasonable, IMHO, if the w_param member is constant so you can calculate the actual_params one time for all and make it static
Probably not the best solution for use in practice, but here's one using a variadically templated lambda to avoid index_sequence:
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
{
return callback(args.t...);
};
return std::apply(helper, w_params);
}
};
Demo
The idea is to just provide a function that matches the arguments that std::apply yields here - it needs to take wrapped<Args>.... From there it's trivial to expand the pack while extracting the wrapped value.
We use a lambda because std::apply wants a Callable, so we can't just use another member function. Well, I guess we could overload operator() for delay_call_with_wrap. That would be mildly confusing but at least not limited to C++2a (and missing compiler support) like templated lambdas.

How to make a SFINAE-based Y combinator in C++?

I was thinking about the implicit templates of C++14, and I'm trying to declare a function to match an specific argument type (SFINAE and traits still give me headaches). I'm not sure how to explain what I want, but I'm trying to make a Y combinator (just to see if it's possible, not intended for production).
I'm trying to declare a function:
template<typename T>
my_traits<T>::return_type Y(T t) {
// ...
};
Such that T is a function (or a functor) that matches
std::function<R(F, Args...)>
// where F (and above return_type) will be
std::function<R(Args...)>
Which would take any number of arguments, but the first should be a function with the same return type and the same arguments (except this function itself). The first parameter to the operator () of the functor is a template.
The usage I want to achieve:
auto fib = [](auto myself, int x) {
if(x < 2)
return 1;
return myself(x - 1) + myself(x - 2);
};
// The returned type of fib should be assignable to std::function<int(int)>
I wasn't able to take the return type of the T type (because of the overloaded operator ()). What I'm trying to make is possible? How could I make it?
Edit:
Seeing it from a different angle, I'm trying to make this work:
struct my_functor {
template<typename T>
char operator () (T t, int x, float y) { /* ... */ };
};
template<typename T>
struct my_traits {
typedef /* ... */ result_type;
/* ... */
};
// I want this to be std::function<char(int, float)>, based on my_functor
using my_result =
my_traits<my_functor>::result_type;
It is not possible in C++14 return type deduction to deduce int(int) out of int(T, int) as OP desires.
However, we can mask the first parameter of the result using the following approach. The struct YCombinator is instantiated with a non-recursive function object member, whose first argument is a version of itself without the first argument. YCombinator provides a call operator that receives the arguments of the non-recursive function and then returns its function object member after substituting itself for the first argument. This technique allows the programmer to avoid the messiness of myself(myself, ...) calls within the definition of the recursive function.
template<typename Functor>
struct YCombinator
{
Functor functor;
template<typename... Args>
decltype(auto) operator()(Args&&... args)
{
return functor(*this, std::forward<Args>(args)...);
}
};
A make_YCombinator utility template allows for a streamlined usage pattern. This compiles run runs in GCC 4.9.0.
template<typename Functor>
decltype(auto) make_YCombinator(Functor f) { return YCombinator<Functor> { f }; }
int main()
{
auto fib = make_YCombinator([](auto self, int n) -> int { return n < 2 ? 1 : self(n - 1) + self(n - 2); });
for (int i = 0; i < 10 ; ++i)
cout << "fib(" << i << ") = " << fib(i) << endl;
return 0;
}
Since the non-recursive function is not defined at time that the recursive function is defined, in general the recursive function must have an explicit return type.
Edit:
However, it may be possible for the compiler to deduce the return type in certain cases if the programmer takes care to indicate the return type of the recursive function before use of the non-recursive function. While the above construction requires an explicit return type, in the following GCC 4.9.0 has no problem deducing the return type:
auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
To pin this down just a bit further, here is a quote from the draft C++14 standard on return type deduction [7.1.6.4.11]:
If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.
Once a return statement has been seen in a function, however, the
return type deduced from that statement can be used in the rest of the
function, including in other return statements. [ Example:
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i; // sum’s return type is int
else
return sum(i-1)+i; // OK, sum’s return type has been deduced
}
—end example ]
It's a really hacky approach, and has severe limitations, but here it goes:
First, we need a class that pretends to support every possible operation (as far as possible), such as the fake_anything class. Note that this isn't perfect since at a minimum . and :: won't work. To fake a functor, we give it a function call operator:
template<class... Ts> fake_anything operator()(Ts&&...) const;
Knowing that the lambda has only one operator(), and that operator() has only one template parameter allows us to extract its signature with decltype(&T::operator()<fake_anything>).
For this to work, the lambda's return type must be explicitly specified; it can't use deduction, since otherwise the deduced return types will probably conflict.
Finally we can obtain the other arguments to the lambda and the return type using the standard partial specialization approach:
template<class T>
struct extract_signature;
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...)> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...) const> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
// other cv- and ref-qualifier versions omitted - not relevant to lambdas
// we can also static_assert that none of Args is fake_anything, or reference to it, etc.
And add an alias template to hide all the ugliness of the hack:
template<class T>
using signature_t = typename extract_signature<decltype(&T::template operator()<fake_anything>)>::type;
And finally we can check that
static_assert(std::is_same<signature_t<decltype(fib)>,
std::function<int(int)>>::value, "Oops");
Demo.
The limitations:
The return type of operator() must be explicitly specified. You cannot use automatic return type deduction, unless all of the return statements return the same type regardless of the return type of the functor.
The faking is very imperfect.
This works for operator() of a particular form only: template<class T> R operator()(T, argument-types...) with or without const, where the first parameter is T or a reference to possibly cv-qualified T.

Capture template parameter of variadic templated arguments

I have the following (incomplete, not-working) definition:
template<typename T, std::function<Args(Context&)>... Funcs>
struct constructor
{
T construct(Context& ctx)
{
return T(Funcs(ctx)...);
}
};
What I want is a templated class - the first argument is the constructed type and all following are functions to be called, the user templates with std::functions that are then called to produce the values for the constructor of type T.
I don't see a possibility to make this code work, let beside capturing the return types of the functions. I want the user to use it like this:
std::function<int(Context&)> ind = [](Context&) {return 2;};
Constructor<int, ind> c;
// c.construct(...) returns 2 by calling the constructor int(int) with argument
// ind(ctx) - which returns 2.
This might be roughly what you're looking for. Keep in mind that a std::function can't be a template parameter.
template <typename R> using Generator = std::function<R (Context&)>;
template <typename T, typename Generators, std::size_t... Is>
T constructImpl(Context& ctx, const Generators& generators,
std::index_sequence<Is...>) {
return T(std::get<Is>(generators)(ctx)...);
}
template <typename T, typename... Args>
class Constructor {
std::tuple<Generator<Args>...> generators;
public:
Constructor(Generator<Args>... generators)
: generators(std::move(generators)...)
{}
T construct(Context& ctx) {
return constructImpl<T>(ctx, generators,
std::index_sequence_for<Args...>());
}
};
Usage:
Constructor<int, int> c([](Context&) { return 2; });
int i = c.construct(context);
assert(i == 2);
Types cannot depend on run time data.
Calling std::function<X(Y)> requires run time data. So your type cannot depend on std::function<X(Y)>, so the type cannot be used as a template parameter.
Now, it can depend on a pointer to a global object: that is interestingly enough not run time state as far as C++ is concerned.
As such, your design is fundamentally flawed.
If you want a function such that it returns 2, this works:
template<class...ignored>
struct Constructor {
template<class... also_ignored>
Constructor(also_ignored&&...) {}
template<class... also_ignored>
int construct(also_ignored&&...) { return 2; }
};
this will pass the unit tests described in your OP, with the exception that you cannot pass ind to Constructor as it is not legal. However, dropping it from the type signature doesn't matter.
If you want more power, we could do this:
template<class T, class... Functors>
struct Constructor {
T construct( Context& ctx ) {
return T( Functors{}( ctx )... );
}
};
in this case you need stateless function objects:
struct ind { int operator()(Context&)const{return 2;} };
much like how std::map requires stateless comparison objects.
If your function objects require state, then you need to store a copy of them for Constructor to access (possibly within Constructor), and you might need the tuple and indexes trick to store them. ("indexes trick" is a helpful google)
I think your Construct can just be a function:
template <typename T, typename... Funcs>
T construct(Context& ctx, Funcs... funcs) {
return T(funcs(ctx)...);
}
Whose usage could be in your example could be:
int x = construct<int>(ctx, [](Context& ) { return 2; });