C++ Templates ByRef vs. ByVal - c++

I'm following an online course (Pluralsight.com) in C++ and struggling with an exercise on templates, in particular passing an actual number (e.g. 3) to a template which expects (T& t).
The code written by the instructor will not compile on my PC - I believe I understand why it will not compile, but want to how it compiled for the instructor (who demos it) and how you should handle this case.
#include "stdafx.h"
#include <iostream>
template <class T>
T myMax(T& t1, T& t2)
{
return t1 < t2 ? t2 : t1;
}
int main()
{
int result = myMax(3, 4);
return result;
}
EDIT: Fixed typo in code (from my experimenting before asking the question). It seems to run in https://ideone.com/1cjJUD so I'm now not sure why it won't compile for me! (Thanks #user4581301)
EDIT2 Post-answer, change name of function to avoid confusion. Should make question clearer to anyone else who stumbles upon the same thing. https://ideone.com/dZffn6
The compiler error is "C2664 'T max<int>(T &,T &)': cannot convert argument 1 from 'int' to 'int &"
This looks to me like it is failing since 3 is an actual number not a reference to a number stored somewhere. Declaring int a=3; and passing a to my max function works fine.
Am I correct about the reason for the compile failure?
How does the instructors code compiles without error? Has this changed in more recent C++ versions (I believe the class uses C++03)?
Is it possible to write a template where I can pass either ByRef or ByVal? Would I end up with 4 cases (a, b); (a&, b); (a, b&); (a&, b&) ?

Because you are returning by value, there's no reason for the parameters to be non-const. rvalues (including literals and temporary objects) are compatible with const references. So that would be a good way to fix it without dealing with all possible combinations:
template <class T>
T myownmax(T const& t1, T const& t2)
{
return t1 < t2 ? t2 : t1;
}
Note that I've renamed the function to avoid ambiguity with std::max. Neil mentioned removing the using namespace std; in a comment -- while that line does trigger the problem, removing it is not a complete solution.
In particular, even without using namespace std;, the code std::complex<double> a, b; auto c = max(a, b); will still find std::max, defeating the whole purpose of making your function a template so it works with any type! This is a consequence of "argument dependent lookup".
So using a different name is the best option.

Related

Implement Clip() in Eigen

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);
}

template function behavor between VC6 and VS2008

I have simple code about template function for Visual C++ 6.0 and Visual Studio 2008.
#include <stdio.h>
#include <vector>
template<typename T>
void function(const std::vector<T> &vec)
{
printf("vector version\n");
}
template<typename T>
void function(T val)
{
printf("value version\n");
}
int main()
{
std::vector<int> vec;
function(vec);
return 0;
}
I tried for each environment, and finally get
at VC6, function of value version, and
at VS2008, function of vector version.
I have 2 questions.
I have recognized priority of overloaded function call as following,
a) specialized function (without implicit type convert)
b) template function (without implicit type convert)
c) specialized function, with implicit type convert
d) template function, with implicit type convert
with this rule, the above results seems that
at VC6, b) is accepted (with <T> = std::vector<int>)
at VS2008, b) is ignored(?) and d) is accepted(?) (with <T> = int)
This means that VC6 is valid and VS2008 is wrong.
Is not my guess correct?
Although, I wish vector version is called for both VC6 and VS2008.
Can I do it?
Regards.
Actually VC6 is wrong; MS had limited support for the C++99 standard (which is when templates were standardized) in VC6 and had better support in VS2005 and up.
Calling function(vec) calls
template<typename T>
void function(const std::template vector<T>& vec)
with T as an int type because the template was deduced from the vector template type (the same as calling function<int>(vec)). If you called function(&vec) then the value function will be called since you're passing in a reference, which gets deduced to function<std::vector<int>>(vec).
If you want it to always call the proper function, then you'll need to be explicit, so you'd need to call it as such:
function< std::vector<int> >(vec)
Which will deduce to the vector version. Note the space between the >, this is to avoid the compiler thinking you meant the stream operator >>.
Hope that helps.

Is visual c++ std::isfinite() standard conforming?

I got a wrapper class that has a simple and light-weighted implicit conversion operator to double.
I like to use it as I would use a double, for example:
if (!std::isfinite(myVar)) ...
But visual c++ implementation of std::isfinite(double) is actually a template that get his argument by copy.
So my wrapper class copy constructor is called, and it is not light-weighted.
To avoid this, I have to write:
if (!std::isfinite((double)myVar)) ...
for every call :(
If visual c++ std::isfinite() was defined as is it on cppreference.com, I would not have to cast every call: ([edit] I may be wrong, Integral isn't an actual type... but... [edit] It still should not accept user defined types ?)
bool isfinite( float arg );
bool isfinite( double arg );
bool isfinite( long double arg );
bool isfinite( Integral arg );
I am not sure what the standard says about this.
Is vc++ template std::isfinite standard-conforming ?
Should I report this as a bug on Microsoft connect ?
Should I define my own isfinite(double) that calls std::isfinite ?
edit
Or maybe it is a non-issue as in a release build the calls get inlined and no copy occurs ? (well I'll try to check it right now and update in a few minutes)
edit 2
It doesn't seem to get inlined in a release build with /Ob2 (inline any suitable function)
edit 3
as requested, a sample:
struct DoubleWrapper {
double value;
DoubleWrapper(double value) : value(value) {
printf("copy Ctor\n");
}
DoubleWrapper(const DoubleWrapper & that) : value(that.value) {}
operator double() const {
return this->value;
}
};
int main() {
DoubleWrapper a(rand()); //rand to prevent optimization
auto res = std::isfinite(a);
printf("%d", res); //printf to prevent optimization
}
edit 4
So, based on Ben Voigt comment, this is what I added to my class header:
#include <cmath>
namespace std {
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
}
Is this a correct solution ?
The only thing is, should I do the same for all <cmath> functions that takes a double ?
edit 5
I'm responding to Shafik Yaghmour answer here, because a comment is too limited (maybe I should start a new question)
If I understand correctly, instead of my edit 4, I should add this to my class header:
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
using std::isfinite;
Is it required to put it in a namespace, or can I leave it in the "global" namespace ?
But this mean I have to change all my calls from std::isfinite(dw) to isfinite(dw).
Ok, but I realize there are many things I don't understand.
I am confused.
I understand that adding an overload to std is not allowed.
However, adding a template specialization is allowed ? Why ? What difference does it makes ?
Anyway, I tried it, and it is not a solution to my problem because this specialization:
template<> inline __nothrow bool std::isfinite(const MagicTarget<double> & mt) {
return std::isfinite((double)mt);
}
will not be selected by the compiler over the standard one:
template<class _Ty> inline __nothrow bool isfinite(_Ty _X)
{
return (fpclassify(_X) <= 0);
}
To be selected, it should be
template<> inline __nothrow bool std::isfinite(MagicTarget<double> mt) {
return std::isfinite((double)mt);
}
But this would still call the copy Ctor :(
Surprisingly the overload (see edit 4) is selected over the standard template...
I am beginning to think that some C++ rules are too subtle for me :(
But, to begin with, why on earth are cmath functions and especially std::isfinite a template ?
What's the point of accepting anything else that floating points types ?
Anyway, vc++ std::isfinite calls std::fpclassify that is only defined for float, double and long double.
So... What's the point?
I am thinking the standard committee screwed up by allowing cmath functions to be templates. They should only be defined for the types that are relevant, or maybe takes their arguments as universal references.
That's it, sorry for the rant...
I will go for the (not in std) overload.
Thank you!
Addressing edit 4 to your question since through the comments you have come close to a final solution.
You should not be adding it to the std namespace, you should add it to one of your own namespace and rely on argument dependent lookup see Is it a good practice to overload math functions in namespace std in c++ for more details.
Given the standard committee's apparent desire to restrict cmath functions to be called with arithmetic types only, relying on an implicit conversion is not a good idea. So performing an explicit conversion via a cast is the safe way to go for all cmath functions:
isfinite((double)dw)
You can find the details of this in Is it valid to pass non-arithmetic types as arguments to cmath functions?.

Does implicit T& constructor of std::reference_wrapper<T> make it dangerous to use?

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).

C++0x decltype fails to deduce member variable constness

Consider the following code:
template <typename T>
class B
{
};
template <typename T>
B<T> f(T& t)
{
return B<T>();
}
class A
{
class C {};
C c;
public:
A() {}
decltype(f(c)) get_c() const { return f(c); }
};
int main()
{
A a;
a.get_c();
}
When I try to compile this, I get the error:
test.cpp: In member function 'B<A::C> A::get_c() const':
test.cpp:31:46: error: conversion from 'B<const A::C>' to non-scalar type 'B<A::C>' requested
It seems that in the decltype, the compiler doesn't know that this is a const member function and therefore c is of type const C, and as a result incorrectly deduces the type of f(c) to be B<C> rather than B<const C> which is what it really is.
Am I doing something incorrectly, or is this a compiler bug? I use gcc 4.6, but 4.4 and 4.5 exhibit the same behaviour.
The compiler operates correctly according to the current C++0x WP. See this issue report, which is currently being worked on.
Possibly the final C++0x Standard won't change the meaning of your decltype application in the return type before the function name. You would need to move it to after the parameter list using -> decltype(f(c)), which hopefully will do The Right thing in final C++0x.
No, decltype is not supposed to take into account whether the function is const or not, because it can't. The same could have been written differently:
typedef decltype(f(c)) return_type;
return_type get_c() const { return f(c); }
Correction: decltype(f(c)) shouldn't even compile, because c is not static.
f needs to take an rvalue reference, not an lvalue reference.
I don't think you're allowed to use decltype on anything you wouldn't normally be able to call. I haven't been able to find anything in the standard that would allow you to access c, even within a decltype expression, outside of anywhere you could use c. Since you don't have a this pointer at the point you're trying to do your thing, I don't think you can do what you're trying to do. Doing so doesn't work in MSVC 2010 at least, and it has nothing to do with const.
I considered using declval to get one but you can't access A&&.c because A is an incomplete type at that point. I can't see anyway to do what you're trying to do other than something like so:
decltype(f(declval<C const>())) get_c() const { ... }