I have code that clips some value to be between a range centered around 0 like below.
Eigen::VectorXd a;
Eigen::VecotrXd b;
a = a.cwiseMin(b).cwiseMax(-b); // no temporary created here?
I want to factor out the logic into a function.
One solution:
Eigen::VectorXd Clip(const Eigen::VectorXd& a, const Eigen::VectorXd& b);
a = Clip(a, b);
But I assume this is inefficient as it creates an extra temporary?
Another solution:
void Clip(Eigen::Ref<Eigen::VectorXd> a, const Eigen::VectorXd& b) {
a = a.cwiseMin(b).cwiseMax(-b);
}
But this seems inconvenient to use sometimes:
void SomeFunctionSignatureICannotChange(const Eigen::VectorXd& a, const Eigen::VectorXd& b) {
// Eigen::VectorXd a_clipped = Clip(a, b); would be cleaner.
Eigen::VectorXd a_clipped;
Clip(a_clipped, b);
}
The best solution I can think of:
template <typename DerivedV, typename DerivedB>
auto Clip(const Eigen::ArrayBase<DerivedV>& v,
const Eigen::ArrayBase<DerivedB>& bound)
-> decltype(v.min(bound).max(-bound)) {
return v.min(bound).max(-bound);
}
(I assume 'auto' in this case is fine and not the one that common pitfalls warned against?)
However, the code seems template-heavy and a bit-complicated. For example, trailing return type is discouraged by google style guide here:
Use the new trailing-return-type form only in cases where it's
required (such as lambdas) or where, by putting the type after the
function's parameter list, it allows you to write the type in a much
more readable way. The latter case should be rare; it's mostly an
issue in fairly complicated template code, which is discouraged in
most cases.
Alternatively, if I remove the trailing return type, function return type deduction will kick in. But google style guide seems to also discourage function return type deduction in public headers here
Furthermore, use it only if the function or lambda has a very narrow
scope, because functions with deduced return types don't define
abstraction boundaries: the implementation is the interface. In
particular, public functions in header files should almost never have
deduced return types.
I'm new to Eigen and C++ so not sure if I missed anything. Hope to learn from everyone's comments and suggestions. Thanks!
I confirm that a = a.cwiseMin(b).cwiseMax(-b); does not create any temporary. In your case, using auto return type is highly recommended, and I would also argue that your use case is a perfectly legit exception to the aforementioned rules:
Writing the return type explicitly would be a nightmare and error prone.
This is a very short function that is expected to be inlined. It is thus expected to be declared and defined at the same time. Therefore the second rule does not not really apply.
In c++14 you can even omit the redundancy:
template <typename DerivedV, typename DerivedB>
auto Clip(const Eigen::ArrayBase<DerivedV>& v,
const Eigen::ArrayBase<DerivedB>& bound)
{
return v.min(bound).max(-bound);
}
Related
I would like to make a universal wrapper function which can accept any
free standing or static function,
member function ( perhaps as a specialization with the first argument used as *this)
including overloaded or templated cases together with variable arguments. Such wrapper will then, in the body, call the function exactly with the forwarded parameters.
Example:
template<typename Fnc,typename...Args>
void wrapper(Fnc fnc, Args&&...args){
// Do some stuff
// Please disregard the case when return type is void,
// that be SFINAED with std::result_of.
auto res = fnc(std::forward<Args>(args)...);
// Do some stuff
return res;
}
#include <vector>
auto foo(int i){ return i; }
auto foo(double& d){ return d; }
auto foo(double&& d){ return d; }
auto foo(const char* str){ return str; }
template<typename...T>
auto generic_foo(T&&...ts){/* ...*/ return /* ...*/; }
template<typename T>
void constrained_foo(std::vector<T>& lref,std::vector<T>&& rref, std::vector<T> value){ /**/}
int main(){
// Basics
wrapper(foo, 1);// foo(int)
wrapper(foo, 1.1); // foo(double&&)
wrapper(foo, "ahoj"); // foo(const char*)
// Conversion must work too
wrapper(foo, 1.1f); // foo(double&&)
wrapper(foo, (short)1); // foo(int)
// Detecting lvalues, rvalues is also a must
double y;
foo(y);
foo(std::move(y));
// Similarly for templates
int x;
std::vector<int> v1, v2, v3;
wrapper(generic_foo, 1, 1.1, "ahoj", x, &x);
wrapper(constrained_foo, v1, std::move(v2), v3);
}
The thing I do find so frustrating about this is that I am supplying all the necessary information to make these calls right next to each other, there is no added ambiguity about what to call, I could call it myself, I could(will) make a macro that can do it, but there is no proper C++ syntax for it AFAIK.
I discovered the need for it while trying to automatically call all my methods in certain "context". But thinking about it more, I believe this could have really widespread usage for <algorithm>, <thread> libraries too. Where you would not have to make one-statement lambdas just to call a function/operator with the lambdas parameters or something captured.
The issue arises in any function accepting another function which will be eventually called together with the passed known parameters.
My attempts
generic_foo can be resolved if the return type is fixed:
template<typename...Args>
void wrapper(void(*f)(Args&&... args) , Args&&...args){
// ...
f(std::forward<Args>(args)...);
}
int main(){
int x;
wrapper(generic_foo, 1, 1.1, "ahoj", x, &x, std::move(x));
}
This works nicely, the return type can maybe be resolved too by some obscure and clever use of std::invoke_result_t, but currently it is a kind of chicken-egg situation with the parameter type. Because the only thing how to resolve the name generic_foo is to force it to decay to a function pointer and then there is no name to put in std::invoke_result_t since the parameter is still being deduced.
This will also work with overloads as long as there is an exact match, so it cannot do conversions.
This approach is as far as I can get without macros when the function name is not known in advance.
If the name of the callable is fixed, there is this frequently-used variation of lambda trick:
template<typename Fnc, typename...Args>
void wrapper(Fnc f , Args&&...args){
// ...
f(std::forward<Args>(args)...);
}
int main(){
int x;
wrapper([](auto&&...args)
{ return generic_foo(std::forward<decltype(args)>(args)...);},
1, 1.1, "ahoj", x, &x, std::move(x));
}
If I add a macro doing exactly this:
#define WRAP_CALL(wrapper_fnc, called_fnc, ...) \
wrapper_fnc([&](auto&&...args) \
{ return called_fnc(std::forward<decltype(args)>(args)...);}, \
__VA_ARGS__ );
int main(){
int x;
WRAP_CALL(wrapper, generic_foo, 1, 1.1, "ahoj", x, &x, std::move(x))
}
I get the least macro-infested working solution I can think of, it works with any callable and any wrappers which can stay proper C++ functions. But I would like macro-less version of this and especially for functions.
So I will probably still use this version, does not seem too unreasonable. Are there any corners cases I should know about?
I did not write a single C++20 concept yet, so I still have very small hope there might be something that can work in that area perhaps? But probably not since std::thread(foo,1); also suffers from it.
So this might sadly require language changes because the name of the overload set or a template cannot currently be passed anywhere, even just as some kind of aggregated type. So perhaps something akin to std::initializer_list class plus its sometimes-magical syntax?
If this is indeed the case, I would gladly accept any answer listing any currently active proposals that might help with this. If there are even any.
I did found N3579 - A Type trait for signatures which could perhaps work together with the function pointer solution if the chicken-egg problem is addressed. But the proposal looks very dead.
The "overloaded or templated cases" are not entities that can be function/template arguments—certain cases where overload resolution can use contextual information notwithstanding. What you mean by foo in your wrapper(foo,…) is little more than a token (in particular, it's an overload set), and the language simply has no way of addressing such an object since it has no ("aggregated"?) type. (Conversely, macros do operate on tokens, which is why they are applicable here.) You seem to know most of this, but it may be helpful to see why it's knowably impossible, and why it's a bad idea to think of an overload set as "a callable". (After all, syntactically a type name is also "callable", but it wouldn't make any sense to pass one as a function argument.)
Even if a call f(g,…) were defined to try each overload of g in turn (which it is, for the narrow purpose of deducing f's template arguments), that wouldn't help for (an overload set containing) a template: there would be no way to even evaluate f's SFINAE conditions given a g template for which a specialization had not yet been chosen.
The standard lambda trick, which you also illustrated, is a way of performing overload resolution with the benefit of the argument list, which is why it's pretty much the only approach that works. There are certainly proposals to automate that process, including the vagaries of SFINAE-friendliness and exception specifications.
Consider this instead:
template <class T>
auto wrapper(T fnc) {
// Do some stuff
auto res = fnc(); // <--- no arguments
// Do more stuff
return res;
}
Since arguments are known at wrapper call time, they can also be bound at wrapper call time.
wrapper([](){ return foo(1); });
wrapper([](){ return foo(1.1); });
wrapper([](){ return foo("ahoj"); });
wrapper([&x](){ return generic_foo(1, 1.1, "ahoj", x, &x); });
You can encapsulate this in a macro, which is of course less than ideal, but at least this one is short and readable.
#define DEFER(x) ([&](){return x;})
wrapper(DEFER(foo(1)));
wrapper(DEFER(foo(1.1)));
wrapper(DEFER(foo("ahoj")));
wrapper(DEFER(generic_foo(1, 1.1, "ahoj", x, &x)));
This doesn't do exactly what you want, for example, in
wrapper(DEFER(foo(bar())))
bar is called late. This is fixable with a bit of syntax:
wrapper([z=bar()](){ return foo(z); });
and of course this can be wrapped in a macro too:
wrapper(DEFER1(foo(z), z=bar()));
although this is getting a bit unwieldy.
This question already has answers here:
Should the trailing return type syntax style become the default for new C++11 programs? [closed]
(4 answers)
Closed 2 years ago.
I have seen people using the following syntax to implement functions:
auto get_next() -> int
{
/// ...
}
Instead of:
int get_next()
{
/// ...
}
I understand both and I know that the trailing return type syntax is useful for template code using decltype. Personally I would avoid that syntax for other code since when reading code I prefer to read the concrete return type of a function first, not last.
Is there any advantage in using the trailing return type syntax for non-template code as shown above (except personal preference or style)?
In addition to sergeyrar's answer, those are the points I could imagine someone might like about trailing return types for non-template functions:
Specifying a return type for lambda expressions and functions is identical w.r.t. the syntax.
When you read a function signature left-to-right, the function parameters come first. This might make more sense, as any function will need the parameters to produce any outcome in the form of a return value.
You can use function parameter types when specifying the return type (the inverse doesn't work):
auto f(int x) -> decltype(x)
{
return x + 42;
}
That doesn't make sense in the example above, but think about long iterator type names.
One potential benefit is that it makes all of your declared function names line up:
auto get_next(int x, int y) -> int;
auto divide(double x, double y) -> double;
auto printSomething() -> void;
auto generateSubstring(const std::string &s, int start, int len) -> std::string;
source: https://www.learncpp.com/cpp-tutorial/the-auto-keyword/
Well you already mentioned the major use case of the trailing return type. It's usage if the return type depends on the arguments.
If we exclude that use case the only advantage you might gain is an enhanced readability of your code, especially if your return type is a bit more complex, but you don't have a technical benefit of using the trailing return in that scenario.
The auto keyword can be used in many contexts and combined with other language elements, as in const auto& or auto&&. However, it cannot be used in cast operations. Consider the following example (which does not compile):
template <class T> void foo(T&& t) {}
int main() {
int i = 0;
foo(static_cast<const auto&>(i)); // This could call foo(const int&)
}
The cast would obviously work with int instead of auto, but being able to use auto in casts would be useful in generic code, for instance:
You could use const auto& (as above) to explicitly call an overloaded function with a const lvalue ref.
Similarly, you could use static_cast<auto&&> as a less verbose version of std::forward<decltype(x)>(x).
Thinking a bit further, static_cast<auto>(x) or something like auto(x) could be a way of explicitly copying an object.
(Note that explicit types instead of auto can be used in all these scenarios.)
To be honest, I intuitively expected this syntax to work (because it mirrors the way auto can be used in declarations), but to my mild surprise it didn't. Since it is such an obvious syntax, I am wondering whether there are specific reasons why it is disallowed? Or is it simply a case of nobody considering/proposing it as a feature?
I want to define a function that takes (besides its usual input arguments) a lambda function. And I want to restrict that function as far as possible (its own input- and return types).
int myfunc( const int a, LAMBDA_TYPE (int, int) -> int mylamda )
{
return mylambda( a, a ) * 2;
}
Such that I can call the function as follows:
int input = 5;
myfunc( input, [](int a, int b) { return a*b; } );
What is the correct way to define myfunc?
And is there a way to define a default lambda? Like this:
int myfunc( const int a, LAMBDA_TYPE = [](int a, int b) { return a*b; });
If you take a std::function<int(int,int)> it will have overhead, but it will do what you want. It will even overload correctly in C++14.
If you do not want type erasure and allocation overhead of std::function you can do this:
template<
class F,
class R=std::result_of_t<F&(int,int)>,
class=std::enable_if_t<std::is_same<int,R>{}>
>
int myfunc( const int a, F&& f )
or check convertability to int instead of sameness. This is the sfinae solution. 1
This will overload properly. I used some C++14 features for brevity. Replace blah_t<?> with typename blah<?>::type in C++11.
Another option is to static_assert a similar clause. This generates the best error messages.
Finally you can just use it: the code will fail to compile if it cannot be used the way you use it.
In C++1z concepts there will be easier/less code salad ways to do the sfinae solution.
1 On some compilers std::result_of fails to play nice with sfinae. On those, replace it with decltype(std::declval<F&>()(1,1)). Unless your compiler does not support C++11 (like msvc 2013 and 2015) this will work. (luckily 2013/3015 has a nice result_of).
There are two alternatives, the type-erasing std::function<signature> forces a particular signature which goes along the lines of your question, but it imposes some additional cost (mainly it cannot be inlined in general). The alternative is to use a template an leave the last argument as a generic object. This approach can be better from a performance point of view, but you are leaving the syntax checking to the compiler (which I don't see as a problem). One of the comments mentions passing a lambda as a function pointer, but that will only work for lambdas that have no capture.
I would personally go for the second option:
template <typename Fn>
int myFunc(const int a, Fn&& f) {
return f(a, a) * 2;
}
Note that while this does not explicitly force a particular signature, the compiler will enforce that f is callable with two int and yields something that can be multiplied by 2 and converted to int.
boost::reference_wrapper<T> has an explicit T& constructor, while std::reference_wrapper<T> has an implicit one. So, in the following code:
foo = bar;
If foo is a boost::reference_wrapper, the code will fail to compile (which is good, since reference_wrapper does not have the same semantics of an actual reference.
If foo is a std::reference_wrapper, the code will "rebind" foo's reference to bar (instead of assigning the value as one might mistakenly expect it to).
This could result in elusive bugs... Consider the following example:
In version 1.0 of some hypothetical library:
void set_max(int& i, int a, int b) {
i = (a > b) ? a : b;
}
In a new version (1.1), set_max is converted to a template to accept integers of any width (or UDT's) without changing the interface:
template<typename T1, typename T2, typename T3>
void set_max(T1& i, T2 a, T3 b) {
i = (a > b) ? a : b;
}
Then finally, in some application using the library:
// i is a std::reference_wrapper<int> passed to this template function or class
set_max(i, 7, 11);
In this example, the library changes its implementation of set_max without changing the call interface. This would silently break any code that passes it a std::reference_wrapper as the argument would no longer convert to int& and would instead "rebind" to a dangling reference (a or b).
My question: Why did the standards committee elect to allow implicit conversion (from T& to std::reference_wrapper<T>) instead of following boost and making the T& constructor explicit?
Edit: (in response to the answer offered by Jonathan Wakely)...
The original demo (in the section above) is intentionally concise to show how a subtle library change could result in the use of std::reference_wrapper introducing bugs to an application.
The next demo is provided to show a real-world, legitimate use of reference_wrapper for "passing references through interfaces", in response to Jonathan Wakely's point.
From Developer/Vendor A
Something similar to std::bind but pretend it's specialized for some task:
template<typename FuncType, typename ArgType>
struct MyDeferredFunctionCall
{
MyDeferredFunctionCall(FuncType _f, ArgType _a) : f(_f), a(_a) {}
template<typename T>
void operator()(T t) { f(a, t); }
FuncType f;
ArgType a;
};
From Developer/Vendor B
A RunningMax functor class. Between version 1.0 and 1.1 of this imaginary library, the implementation of RunningMax was changed to be more generic, without changing its call interface. For purposes of this demo, the old implementation is defined in namespace lib_v1, while the new implementation in defined in lib_v2:
namespace lib_v1 {
struct RunningMax {
void operator()(int& curMax, int newVal) {
if ( newVal > curMax ) { curMax = newVal; }
}
};
}
namespace lib_v2 {
struct RunningMax {
template<typename T1, typename T2>
void operator()(T1& curMax, T2 newVal) {
if ( newVal > curMax ) { curMax = newVal; }
}
};
}
And last but not least, the end-user of all the above code:
Some developer using the code from Vendor/Developer A and B to accomplish some task:
int main() {
int _i = 7;
auto i = std::ref(_i);
auto f = lib_v2::RunningMax{};
using MyDFC = MyDeferredFunctionCall<decltype(f), decltype(i)>;
MyDFC dfc = MyDFC(f, i);
dfc(11);
std::cout << "i=[" << _i << "]" << std::endl; // should be 11
}
Note the following:
The end-user uses std::reference_wrapper the way in which it's intended.
Individually, none of the code has bugs or logical flaws, and everything worked perfectly with the original version of Vendor B's library.
boost::reference_wrapper would fail to compile upon upgrading the library, while std::reference_wrapper silently introduces a bug that may or may not be caught in regression tests.
Tracing such a bug would be difficult, since the "rebinding" is not a memory-error that tools such as valgrind would catch. Furthermore, the actual site of the misuse of std::reference_wrapper would be within Vendor B's library code, not the end-user's.
The bottom line: boost::reference_wrapper seems safer by declaring its T& constructor as explicit, and would prevent the introduction of a bug such as this. The decision to remove explicit constructor restriction in std::reference_wrapper seems like it compromised safety for convenience, something that should rarely occur in language/library design.
This would silently break any code that passes it a std::reference_wrapper as the argument would no longer convert to int& and would instead "rebind" to a dangling reference (a or b).
So don't do that.
reference_wrapper is for passing references through interfaces that would otherwise make a by-value copy, it's not for passing to arbitrary code.
Also:
// i is a std::reference_wrapper<int> (perhaps b/c std::decay wasn't used)
decay wouldn't change anything, it doesn't affect reference wrappers.
The reason implicit conversion (T& --> reference_wrapper<T>) is allowed for std::reference_wrapper<T>, but not boost::reference_wrapper<T>, is sufficiently explained in the DR-689 link provided by Nate Kohl. To summarize:
In 2007, the C++0x/C++11 Library Working Group (LWG) proposed change #DR-689 to section 20.8.3.1 [refwrap.const] of the standard:
The constructor of reference_wrapper is currently explicit.
The primary motivation behind this is the safety problem with respect
to rvalues, which is addressed by the proposed resolution of [DR-688].
Therefore we should consider relaxing the requirements
on the constructor since requests for the implicit conversion keep
resurfacing.
Proposed resolution: Remove explicit from the constructor of reference_wrapper.
It's worth pointing out:
boost::reference_wrapper has not been relaxed in such a way, nor does there appear to be a proposal for it, which creates an inconsistency between the semantics of boost::reference_wrapper and std::reference_wrapper.
Based on the verbiage in DR-689 (specifically the "requests keep surfacing" part) it seems likely that this change was simply viewed by the LWG as an acceptable tradeoff between safety and convenience (in contrast to its boost counterpart).
It's unclear whether the LWG anticipated other potential risks (such as those demonstrated in the examples provided on this page), since the only risk mentioned in DR-689 was that of binding to an rvalue (as described and resolved in the previous entry, DR-688).