Generic functions taking generic functions as arguments - c++

I can't find a nice way to define generic higher-order functions taking generic functions as arguments. For example, take this attempt at one of the simplest such functions out there:
template<typename F, typename A>
auto apply(F f, const A& a) -> decltype(f(a)){return f(a);}
Of course it works as intended when used with non-template functions. But if I have, for instance
template<typename A>
A id(const A& a){return a;}
then
int a = 10;
int b = apply(id, a);
will not work, since id expects a template parameter. I could just write id<int> to make it work, but that sort of defeats the purpose (as I see it, it implies that if I wanted to write "filter" I'd have to write a separate definition for each generic predicate function). Using std::function or function pointers did not help. Also, I tried to make a "template template" version of apply, but I get various compiler errors when I try to use it:
template<template<typename> class F, typename A>
auto apply2(F<A> f, const A& a)-> decltype(f(a)){return f(a);}
The best I came up with was the following:
struct Id{
template<typename A>
static A func(const A& a){return a;}
};
template<typename F, typename A>
auto apply(A a)-> decltype(F::func(a)){return F::func(a);}
It's a bit ugly, but now at least I can actually parameterize by the function.
So, is there a better way to do generic functions taking generic functions as arguments?

This 'functor' works with your first version of apply.
struct id
{
template<typename A>
A operator ()(const A& a) {return a;}
};
later
int b = apply(id(), a); // with extra parenthesis to construct the struct.

In C++11 the best you can do is to use a struct with a templatized function call operator:
struct ID {
template <typename T>
void operator()(T arg) const {
...
}
};
The reason this is preferrable to a function [pointer] because it more likely to be inlined. With C++14 you could use lambdas:
[](auto arg){ ... }
which is just a cute version to write the struct above.

Related

std::span<const T> as parameter in function template

In the following library functions f and g, I use std::span<const T> to remind the user of the library of the contract that f and g will not modify the contents of the span. The user of the library holds std::span<int> a, which is convertible to std::span<const int>. Hence, the user can call g(a) as expected. However, the user cannot call f(a), since f is a function template and a is not of the required type; conversions do not apply here. Can you see a (sane) way to have f take in std::span<const T> while still accepting std::span<T>?
#include <span>
void g(const std::span<const int>& a) {}
template <typename T>
void f(const std::span<const T>& a) {}
int main()
{
std::span<int> a;
// OK
g(a);
// No match
f(a);
// OK
f((std::span<const int>)a);
}
It is possible to add an overload like this:
template <typename T>
void f(const std::span<T>& a) {
return f((std::span<const T>)a);
}
But I'm not sure if I count this as sane, since then I would be writing these overloads to every function template which takes in std::span<const T>.
EDIT: Not the same case, but if f also happens to take in another parameter which mentions T, then one can do the following:
template <typename T> using NoDeduction = std::type_identity_t<T>;
template <typename T>
void f(NoDeduction<std::span<const T>> a, const T& b) {}
After which f(a, 1); works. This is a partial solution. The original problem still remains.
EDIT 2: I was wondering whether the above technique works also when we include span's compile-time size:
template <typename T, std::size_t N>
void f(const std::span<NoDeduction<const T>, N>& a, const T& b) {}
Gcc 10.1 compiles it, MSVC 16.6.2 and Clang 10.0.0 don't. I filed bug reports for both MSVC and Clang.
You can generalize your overload to be a utility like std::as_const:
template<class T>
std::span<const T> const_span(std::span<T> s) {return s;}
The caller then has to decorate their calls with mutable spans, but in so doing indicates to the reader that no modification is allowed.
Another, unconventional workaround would be to make your function be a class and use deduction guides:
template<class T>
struct f {
f(std::span<const T>);
// operator ReturnType();
};
template<class T> f(std::span<T>)->f<T>;
It’s debatable whether the interface describes the intent here.
It is unable to make the type conversion because it fails to deduce the type as f is a template.
If you want to write template function f that accepts various input types - you'd better write it as
template<typename Viewer>
void f(const Viewer& a){...}
If you want to work with span then you can implement it in two steps:
template<typename T>
void f_impl(std::span<const T> a){...}
template<typename Viewer>
void f(const Viewer& a)
{
f_impl(std::span<const typename Viewer::value_type>(a.data(),a.size()));
}
P.S. with span you should normally take copy of it instead of "const reference". This is more efficient.

Deducing the template parameter of a templated class argument: const issue

I think the problem is fairly common, so there should be a known solution. I came up with one, but I'm not really satisfied, so I'm asking here, hoping someone can help.
Say I have a function, whose signature is
template<typename T>
void foo(const MyArray<const T>& x);
The const in the template parameter is to prevent me from changin the array content, since (for reasons beyond this question), the accessors ([] and ()) of MyArray<T> are always marked const, and return references to T (hence, the const ensure safety, since MyArray<T>::operator[] returns T&, while MyArray<const T>::operator[] returns const T&).
Great. However, templates with different template arguments are non related, so I can't bind a reference to MyClass<T> to a reference of MyClass<const T>, meaning I can't do this
MyArray<double> ar(/*blah*/);
foo(ar);
Notice that, without a reference, the code above would work provided that there is a copy constructor that lets me create MyArray<const T> from MyArray<T>. However, I don't want to remove the reference, since the array construction would happen a lot of times, and, despite relatively cheap, its cost would add up.
So the question: how can I call foo with an MyArray<T>?
My only solution so far is the following:
MyArray<T> ar(/*blah*/);
foo(reinterpret_cast<MyArray<const T>>(ar));
(actually in my code I hid the reinterpret cast in an inlined function with more verbose name, but the end game is the same). The class MyArray does not have a specialization for const T that makes it not reinterpretable, so the cast should be 'safe'. But this is not really a nice solution to read. An alternative, would be to duplicate foo's signature, to have a version taking MyArray<T>, which implementation does the cast and calls the const version. The problem with this is code duplication (and I have quite a few functions foo that need to be duplicated).
Perhaps some extra template magic on the signature of foo? The goal is to pass both MyArray<T> and MyArray<const T>, while still retaining const-correctness (i.e., make the compiler bark if I accidentally change the input in the function body).
Edit 1: The class MyArray (whose implementation is not under my control), has const accessors, since it stores pointers. So calling v[3] will modify the values in the array, but not the members stored in the class (namely a pointer and some smart-pointer-like metadata). In other words, the object is de facto not modified by accessors, though the array is. It's a semantic distinction. Not sure why they went this direction (I have an idea, but too long to explain).
Edit 2: I accepted one of the two answers (though they were somewhat similar). I am not sure (for reasons long to explain) that the wrapper class is doable in my case (maybe, I have to think about it). I am also puzzled by the fact that, while
template<typename T>
void foo(const MyArray<const T>& x);
MyArray<int> a;
foo(a);
does not compile, the following does
void foo(const MyArray<const int>& x);
MyArray<int> a;
foo(a);
Note: MyArray does offer a templated "copy constructor" with signature
template<typename S>
MyArray(const MyArray<S>&);
so it can create MyArray<const T> from MyArray<T>. I am puzzled why it works when T is explicit, while it doesn't if T is a template parameter.
I would stay with
template<typename T>
void foo(const MyArray<T>&);
and make sure to instantiate it with const T (in unitTest for example).
Else you can create a view as std::span.
Something like (Depending of other methods provided by MyArray, you probably can do a better const view. I currently only used operator[]):
template <typename T>
struct MyArrayConstView
{
MyArrayConstView(MyArray<T>& array) : mArray(std::ref(array)) {}
MyArrayConstView(MyArray<const T>& array) : mArray(std::ref(array)) {}
const T& operator[](std::size_t i) {
return std::visit([i](const auto& a) -> const T& { return a[i]; }), mArray);
}
private:
std::variant<std::reference_wrapper<MyArray<T>>,
std::reference_wrapper<MyArray<const T>>> mArray;
};
and then
template <typename T>
void foo(const MyArrayConstView<T>&);
but you need to call it explicitly, (as deduction won't happen as MyArray<T> is not a MyArrayConstView)
MyArray<double> ar(/*blah*/);
foo(MyArrayConstView{ar});
foo<double>(ar);
Since you are not allowed to change MyArray, one option is to use an adapter class.
template <typename T>
class ConstMyArrayView {
public:
// Not an explicit constructor!
ConstMyArrayView(const MyArray<T>& a) : a_(a) {}
const T& operator[](size_t i) const { return a_[i]; }
private:
const MyArray<T>& a_;
};
template<typename T>
void foo(const ConstMyArrayView<T>& x);
MyArray<T> x;
foo(x);
But in the end, if you can change MyArray to match the const-correctness you want, or switch to a class that does, that'll be the better option.
Here's an ugly but effective way to have a function use one type, but also get the compiler to check that the same code would compile if it used a different type instead:
template <typename From, typename To>
struct xfer_refs_cv
{
using type = To;
};
template <typename From, typename To>
struct xfer_refs_cv<const From, To>
{
using type = const typename xfer_refs_cv<From, To>::type;
};
template <typename From, typename To>
struct xfer_refs_cv<volatile From, To>
{
using type = volatile typename xfer_refs_cv<From, To>::type;
};
template <typename From, typename To>
struct xfer_refs_cv<From&, To>
{
using type = typename xfer_refs_cv<From, To>::type&;
};
template <typename From, typename To>
struct xfer_refs_cv<From&&, To>
{
using type = typename xfer_refs_cv<From, To>::type&&;
};
template <typename CheckType, typename Func, typename CallType>
constexpr decltype(auto) check_and_call(Func&& f, CallType&& call_arg)
noexcept(noexcept(std::forward<Func>(f)(std::forward<CallType>(call_arg))))
{
(void) decltype(std::declval<Func&&>()
(std::declval<typename xfer_refs_cv<CallType&&, CheckType>::type>()), 0){};
return std::forward<Func>(f)(std::forward<CallType>(call_arg));
}
template<typename T>
void foo(const MyArray<T>& x)
{
check_and_call<MyArray<const T>>(
[](auto&& x) {
// Function implementation here.
}, x);
}

Template for a family of functions designed to copy/convert objects

I would like to write a family of copy/conversion functions named copy that copies from object A to object B. For instance
void f(const A& a) {
B b = copy<B>(a);
...
}
For instance A could be a std::array<double, 5> and B could be a std::vector<double>.
Is it possible to do such a thing and define for once the specialization that converts from any std::array<T, n> to std::vector<T>? In another file I would also like to define for once the specialization that converts from any std::array<T, n> to CudaVector<T>. In another file I would like to define the conversion from SparseMatrix<T> to DenseMatrix<T>, etc...
If you don't find any solution for that, do you think of any way to do something similar, as long as I still have value semantics (I don't want to define copy(const A& input, B& output)).
This is certainly possible thanks to template argument deduction. The from-type can be deduced from the argument, the return type needs to be explicitly stated.
There's one other problem and that is that if the plan is to have specializations for converting various containers to various other containers, you would need partial function specializations, which are not allowed. But an usual trick can work around that using partial specializations of classes instead.
For example, this works as a generic template and its specialization for copy-converting a std::array to a std::vector of the same element type:
template<typename B, typename A>
struct copier {
//static B copy(const A&); // Is there a generic fall-back algorithm? Probably not.
};
template<typename T, size_t N>
struct copier<std::vector<int>, std::array<T, N>> {
static std::vector<int> copy(const std::array<T, N>& a) {
std::vector<int> b{};
std::copy(a.begin(), a.end(), std::back_inserter(b));
return b;
}
};
template<typename B, typename A>
B mcopy(const A& a) {
return copier<B, A>::copy(a);
}
Then you can call this using
std::array<int, 3> a{1, 2, 3};
using B = std::vector<int>;
B b = mcopy<B>(a);
which looks just like the line from your question.
Note that copy is not a very good name for this function. ADL would kick in and find std::copy as long as the type A is in namespace std, which might lead to very strange error messages.

Endofunctor concept or interface

From here on a (endo)functor is something able to take an object and transform it in another object of the same type. The simplest example of functor is the identity:
struct Identity {
template <typename T>
T Apply(T x) {
return x
}
};
I need to have a "Functor type" that identifies a generic Functor. What I would like to do is write code like:
class Sum {
public:
Sum(Functor* f, Functor* g) :
f_(f),
g_(g) {}
template <typename T>
T Apply(T x) { return f_->Apply(x) + g_->Apply(x); }
private
Functor* f_;
Functor* g_;
};
The first idea that came to my mind is of course using a virtual class:
struct Functor {
template <typename T>
virtual T Apply(T x) = 0;
};
The unsolvable problem with this approach is that templates cannot be virtual.
Then I tried using C++ concepts. But, as stated in Specifying a concept for a type that has a member function template using Concepts Lite and
C++ Concepts: Can I define a concept that is itself a template? it is not possible to have a "templated concept".
Finally I have stumbled upon How to achieve "virtual template function" in C++ and therefore I came up with the following possible implementation:
struct Functor {
template <typename T>
T Apply(const T& x); // No more virtual!!!
};
// ... Identity and Sum declarations properly inheriting from Functor ...
template <typename T>
T Functor::Apply(T x) {
if (Identity* specialized =
dynamic_cast<Identity*>(this)) {
return specialized->Apply(x);
} else if (const Sum* specialized =
dynamic_cast<const Sum*>(this)) {
return specialized->Apply(x);
} else ...
}
Even though this is compiling, it's not the best solution. The main issues are: performance and code repetition.
The performance issue comes from the fact that each time Apply is called on a Functor the long if clause inside Functor::Apply must be resolved. This is a big problem as Functor can be deeply nested (so calling Apply may result in multiple call to Functor::Apply). The "code repetition" issue is quite self evident as each time I want to define a new Functor I have also to modify Functor::Apply adding a new if clause.
What I am asking here is whether there is a proper (cleaner) way to define a Functor interface/concept that makes possible creating classes like Sum.
C++ concepts and heavy template metaprogramming is accepted.
p.s. All the code snippets have been kept as simple as possible on purpose. Avoid suggesting to use class instead of struct or to add const identifiers or to use unique pointers, it's not the point of this question.
Most of the (best) solutions I can think of unfortunately require that you adopt some fairly complex methodologies. Which isn't necessarily a bad thing, of course, but it can make things confusing as you move forward with designing a program. For that reason, I'd probably suggest something a little more straight-forward:
template <typename F, typename G>
class Sum {
public:
Sum(F& f, G& g) :
f_(f),
g_(g) {}
template <typename T>
inline T Apply(T x) { return f_.Apply(x) + g_.Apply(x); }
private:
F& f_;
G& g_;
};
/*
For every class like the above, you may want to define an
easy-to-use generating function to simplify instantiations:
*/
template <typename F, typename G>
inline Sum<F, G> MakeSum(F& f, G& g)
{
return Sum<F, G>(f, g);
}
#include <cmath>
struct SquareRoot {
template <typename T>
inline T Apply(T x)
{
return std::sqrt(x);
}
};
struct Triple {
template <typename T>
inline T Apply(T x)
{
return T(3) * x;
}
};
// Example:
#include <iostream>
int main(void)
{
using namespace std;
SquareRoot square_root;
Triple triple;
// For g++, don't forget to compile with -std=c++1z
auto sum = MakeSum(square_root, triple);
cout << sum.Apply(1024) << endl;
}
Granted, it isn't as powerful as other techniques, but it may be a good starting point nonetheless.

Explicit specialization using variadic parameters within variadic templated class [MSVS '12: Nov. '12 CTP: error C3522]

I'm trying to expand a class's variadic template type list within a child method as such:
template<typename... P>
struct Foo
{
template<P...> // error C3522: 'P' : parameter
// pack cannot be expanded in this context
static void Bar(P... a){}
};
What is wrong with this code, or is it just a MSVS '12: Nov. '12 CTP bug?
(Yes, I know the explicit template specialization in this example is redundant.)
The above is the simplest case that I get to reproduce the error. The full code is:
template<typename FuncSignature>
class Callback;
template<typename R, typename... P>
class Callback<R (P...)>
{
public:
Callback() : func(0), obj(0) {}
Callback& operator=(const Callback& rhs)
{ obj = rhs.obj; func = rhs.func; return *this; }
private:
typedef R (*FuncType)(const void*, P...);
Callback(FuncType f, const void* o) : func(f), obj(o) {}
private:
FuncType func;
const void* obj;
template<typename FR, typename... FP>
friend class FreeCallbackFactory;
};
template<typename R, typename... P>
class FreeCallbackFactory
{
private:
template<R (*Func)(P...)>
static R Wrapper(const void*, P... a)
{
return (*Func)(a...);
}
public:
template<R (*Func)(P...)>
inline static Callback<R (P...)> Bind()
{
return Callback<R (P...)>
(&FreeCallbackFactory::Wrapper<Func>, 0);
}
};
template<typename R, typename... P>
inline FreeCallbackFactory<R, P...>
GetCallbackFactory(R (*)(P...))
{
return FreeCallbackFactory<R, P...>();
}
void Test(){}
int main(int argc, char** argv){
Callback<void ()> cb = GetCallbackFactory(&Test).Bind<&Test>()
}
It compiles fine in g++ so I'm assuming just a compiler bug, and continued findings still only point to this, are there any possible workarounds for this other than explicitly expanding them out one by one?
Edit: This has been reported to the compiler team as a bug and a patch will be in the next release of the compiler. [Link]
The code looks correct put I doubt that it does what you intended it to do: The declaration
template <P...>
static void Bar(P... a);
declares a function taking P... values as template argument and as function argument. That is, the elements of P need to be of a type allowing non-type parameters (e.g., integers, pointers, or references) and you'd need to provide their respective values as template parameters when calling the function. The call to a function like this would look something like this (although it seems neither gcc nor clang require the template parameters to be passed):
Foo<int, int>::Bar<1, 2>(3, 4);
That said, based on the error messages generated by both gcc and clang it seems that they won't let you create a specialization of member function templates but I haven't verified this in the standard. I think, you should probably just leave out the template declaration and use
static void Bar(P... a);
To me the code does not look correct. The pack expansion P... expands to a set of types. Depending on what you aim to achieve the correct thing to do would be to remove the template<P...> part, in which case each class template instance has one Bar() method with the same parameters as the class. The other would be that this is an unrelated parameter pack in which case an unbounded set of methods is generated, in that case you must declare the method something like:
template<typename... U> static void Bar(U...);
reusing the name P would not be very useful, I guess.