I program in C# a majority of the time, so I'm always used to using the "=>" operator for single-line methods like this:
int AddNums(int a, int b) => return a + b;
But as far as I know, the only way to do this in C++ is by using brackets:
int AddNums(int a, int b) {
return a + b;
}
I'd like to be able to use the single-line convention that I'm used to, but I'm not even sure what it's called. Is this even possible in C++?
Not really.
You could format it in a different way
auto AddNums(int a, int b) -> int { return a + b; }
Or write a lambda
auto add_nums = [](int a, int b){ return a + b; }
You'd still going to need those braces to delimit the body of the function.
Related
Excuse any mistakes in my code, I'm still learning C++ syntax. My question is not about whether the code is correct but whether a literal expression will be optimized away.
Let's say I have a function generated from a non-type template like this:
template <bool add>
int addIt(int a, int b) {
if (add) {
return a + b;
} else {
return a - b;
}
}
int v = addIt<true>(10, 5);
From my understanding, the compiler should expand the template to:
int addIt_someID(int a, int b) {
if (true) {
return a + b;
} else {
return a - b;
}
}
int v = addIt_someID(10, 5);
But since it now says if (true) it should be able to remove that entire branch, resulting in this:
void addIt_someID(int a, int b) {
return a + b;
}
int v = addIt_someID(10, 5);
This should be standard compiler behavior... but is this behavior well enough established that I can be certain of it from all major compilers?
I'm relying upon this behavior for a transpiler, and if it's not guaranteed I will have to implement it myself... if it is guaranteed I can let the C++ compiler to do it and that will save me a lot of time in having to parse and evaluate this myself.
This is never guaranteed for regular if (although I would say chaneces are pretty high). There are two ways to be sure. Simpler one requires C++17 (btw addIt seems to return wrong type):
template <bool add>
int addIt(int a, int b) {
if constexpr (add) {
return a + b;
} else {
return a - b;
}
}
int v = addIt<true>(10, 5);
if constexpr guerantees that this will be evaluated in compile time.
Another option is using template metaprogramming/explicit template specialization. For your code this would be pretty simple:
template <bool add>
int addIt(int a, int b);
template<> int addIt<true>(int a, int b) { return a + b; }
template<> int addIt<false>(int a, int b) { return a - b; }
int v = addIt<true>(10, 5);
For other cases you would need some more work like using std::enable_if and stuff like this
I have a bunch of code like the following:
int sign(MyEnum e)
{
switch(e)
{
case A:
case B:
return 1;
case C:
case D:
return -1;
default:
throw std::runtime_error("Invalid enum value");
}
}
int f(int a, int b, int c, MyEnum e)
{
const int sign = sign(e);
const int x = a * b - sign * c;
const int y = a + sign * c;
return x / y;
}
The arithmetic here is just an example. The actual code is more complex, but the point is that sign is either -1 or 1 depending on an enum value, and we do a bunch of calculations where various things are multiplied by sign. (Edit: the enum value is not known at compile time.)
I'd like this code to be optimized as though I'd written something like the following:
int f(int a, int b, int c, MyEnum e)
{
switch(e)
{
case A:
case B:
{
const int x = a * b - c;
const int y = a + c;
return x / y;
}
case C:
case D:
{
const int x = a * b + c;
const int y = a - c;
return x / y;
}
default:
throw new std::runtime_error("Invalid enum value");
}
}
Of course I don't actually want to write all the code like that, because it's a testing and maintenance nightmare.
Playing around with Compiler Explorer, it looks like the exception in sign may be the issue here; if I have the "default" case return, say, -1, then I get what I want. But I would like some safety here.
Questions:
Is there a fundamental reason that throwing an exception prevents (or discourages the compiler from using) this optimization?
It looks like compiling this at -O3 makes two clones of the method, one of which does what I want, although I don't know which one actually would get run. Can I give hints for this?
I don't know if I want to compile everything at -O3. Can I turn on optimizations for just a particular block of code, or encourage the compiler to make them?
Is there some fancy template metaprogramming trick or something I can use to write code that looks like the first block but which generates code looking like the second block?
Any other suggestions for what I'm trying to do?
EDIT: Since I (obviously) don't understand all the issues at hand I probably didn't give this a great title. Please feel free to edit if you know what you're doing.
Here's an alternative take on the thing:
template <int sign>
int f(int a, int b, int c)
{
const int x = a * b - sign * c;
const int y = a + sign * c;
return x / y;
}
int f(int a, int b, int c, MyEnum e)
{
const int sign = sign(e);
if (sign == 1) return f<1>(a, b, c);
else return f<-1>(a, b, c);
}
This way, you keep the safety you want (in the form of the exception), but then transform the resulting information into a compile-time value which the compiler can use for optimisations.
As Chris pointed out in comments, if sign is only ever used to switch the sign of c, you can get rid of the template altogether and just flip c's sign when calling:
int f(int a, int b, int c)
{
const int x = a * b - c;
const int y = a + c;
return x / y;
}
int f(int a, int b, int c, MyEnum e)
{
const int sign = sign(e);
if (sign == 1) return f(a, b, c);
else return f(a, b, -c);
}
Since in this situation, int sign(MyEnum) function it not used by other translation units, then it could be marked static.
In this context, static means that the function is local to the translation unit, and does not link outside of this translation unit. (The keyword static has different meanings in C++ depending on the context it is used.)
That allows the optimizers to perform more optimizations and possibly eliminate the function entirely (assuming optimization is enabled).
I want to have two version a function by hiding or not hiding several lines of code at the middle and also near the end of the function with template or other means. How to do that?
The functions are performance critical. They got run a gazillion of gazillion times.
You could implement the first one with a default parameter:
int A(int a, int b, int c, int d = 0)
{
// stuff
}
You can factor out the common part and use a function object to pass the differing part:
template<class Fun>
int AB(Fun&& fun){
int x = 0;
Outer Loop{
Inner Loop{
x = std::forward<Fun>(fun)();
}
}
return x;
}
int a, b, c, d;
// ... initialize
int result1 = AB([a,b,c]{
return a + b;
});
int result2 = AB([a,b,c,d]{
return a + b + c*d;
});
You could make this even more general by templating the return type.
There are no branches and an optimizing compiler will be able to expand the function call inline. The latter is the reason to prefer function objects to function pointers.
Honestly, I would suggest you to re-implement your code. But the one thing that is coming to my mind is using function as parameter, see below (you may also use lambda expression):
int fun1(int a, int b, int c, int d) {
return a + b;
}
int fun2(int a, int b, int c, int d) {
return a + b + c*d;
}
template <int (*FUN)(int, int, int, int)> int fun_main(int a, int b, int c, int d = 0) {
int x = 0;
Outer Loop{
Inner Loop{
x += FUN(a, b, c, d);
}
}
return x;
}
Then somwhere in your code:
fun_main<fun1>(1, 2, 3, 4);
Can you use templates (or the like) in C++ to specify which operation is done in a function?
I don't know how to explain it more clearly, so I'll show you how it could be (but isn't) done in code:
template <operator OPERATION> int getMaxOrMin(int a, int b) {
return a OPERATION b ? a : b;
}
where finding the maximum or the minimum of a or b would be (this is where my pseudo-syntax gets a little confusing, bear with me):
int max = getMaxOrMin< > > (a, b);
int min = getMaxOrMin< < > (a, b);
I know that's not how to do it at all (because it doesn't even syntactically make sense), but I hope that clarifies the type of thing I want to do.
The reason behind me wondering this is I'm making a PriorityQueue implementation, and it would be nice to easily switch between the backing being a max-heap or a min-heap on the fly without copying and pasting code to make two different classes.
I know I could do it with a macro, but the only way I'd know how to do that would give me either a max-heap or a min-heap, but not both in the same compilation. I'm probably overlooking a way, though.
Do what std::map and friends do: Take a comparison function/functor as your template parameter. See std::less and std::greater.
Do remember that the standard library already has a well developed and debugged priority queue that you can use with an arbitrary comparison function.
Yes but you need to define it like a functor:
template <typename OPERATION>
int getMaxOrMin(int a, int b)
{
OPERATION operation;
return operation(a, b) ? a : b;
}
Now you can use it like this:
struct myLess
{
bool operator()(int a,int b) const { return a < b; }
}
struct myGreat
{
bool operator()(int a,int b) const { return a > b; }
}
void code()
{
int x = getMaxOrMin<myLess>(5,6);
int y = getMaxOrMin<myGreat>(5,6);
}
That seems like a lot of work. But there are a lot of predefined functors in the standard. On this page scroll down to "6: Function Objects".
For your situation there is:
std::less
std::greater
So the code becomes:
template <typename OPERATION>
int getMaxOrMin(int a, int b)
{
OPERATION operation;
return operation(a, b) ? a : b;
}
void codeTry2()
{
int x = getMaxOrMin<std::less<int> >(5,6);
int y = getMaxOrMin<std::greater<int> >(5,6);
}
Is it possible to use previous arguments in a functions parameter list as the default value for later arguments in the parameter list? For instance,
void f( int a, int b = a, int c = b );
If this is possible, are there any rules of use?
The answer is no, you can't. You could get the behaviour you want using overloads:
void f(int a, int b, int c);
inline void f(int a, int b) { f(a,b,b); }
inline void f(int a) { f(a,a,a); }
As for the last question, C doesn't allow default parameters at all.
No, that is not legal C++. This is specified in section 8.3.6/9 of the C++ Standard:
Default arguments are evaluated each
time the function is called. The
order of evaluation of function arguments
is unspecified. Consequently,
parameters of a function shall not be
used in default argument expressions,
even if they are not evaluated.
and:
int f(int a, int b = a); // error:
parameter a used as default argument
And C89 at least does not support default parameter values.
As a potential workaround, you could do:
const int defaultValue = -999; // or something similar
void f( int a, int b = defaultValue, int c = defaultValue )
{
if (b == defaultValue) { b = a; }
if (c == defaultValue) { c = b; }
//...
}
This is not possible
No, you cannot do that.You will surely get an error "Local variable may not appear in this context".
Your first idea might be to do something like this :
void something(int a, int b=-1, int c=-1){
if(b == -1)
b = a;
if(c == -1)
c = b;
}
I used -1 because this function only works with positive values. But what if someone uses my class and makes a mistake which ends up sending -1 to the method? It would still compile and execute, but the result would be unpredictable for the user. So the smart thing to do would be to remove any default argument and instead make a bunch of methods with the same name like this:
void something(int a, int b, int c){
/* Do something with a, b and c */
}
void something(int a){
something(a, a, a);
}
void something(int a, int b){
something(a, b, b);
}
It doesn't really take much longer to code, and if someone uses it in a programming interface with auto-complete features, it will show the 3 possible prototypes.
I do not think you can do that as that is an illegal syntax. But however, consult the C99 standard in pdf format (n1136.pdf).
However, you may get around this by using static as in declaring the variables static and using them within the function f
static int global_a;
/* In some other spot where you are calling f(), do this beforehand */
/* global_a = 4; f(); */
void f(void){
int a = global_a;
b = c = a;
/* ..... */
}
Kudos to Michael Burr for pointing out my error! :)
It sounds like you need to rethink your code and change it around for something like that.