Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible in C++ to use the same code with and without compile time constants?

Tags:

c++

say you have a function like:

double do_it(int m)
{
   double result = 0;

   for(int i = 0; i < m; i++)
      result += i;

   return result;
}

If you know m at compile time you can do:

template<size_t t_m>
double do_it()
{
   double result = 0;

   for(int i = 0; i < t_m; i++)
      result += i;

   return result;   
}

This gives a possibility for things like loop unrolling when optimizing. But, sometimes you might know some cases at compile-time and some at run-time. Or, perhaps you have defaults which a user could change...but it would be nice to optimize the default case.

I'm wondering if there is any way to provide both versions without basically duplicating the code or using a macro?

Note that the above is a toy example to illustrate the point.

like image 212
user109078 Avatar asked Dec 31 '22 18:12

user109078


2 Answers

In terms of the language specification, there's no general way to have a function that works in the way you desire. But that doesn't mean compilers can't do it for you.

This gives a possibility for things like loop unrolling when optimizing.

You say this as though the compiler cannot unroll the loop otherwise.

The reason the compiler can unroll the template loop is because of the confluence of the following:

  1. The compiler has the definition of the function. In this case, the function definition is provided (it's a template function, so its definition has to be provided).

  2. The compiler has the compile-time value of the loop counter. In this case, through the template parameter.

But none of these factors explicitly require a template. If the compiler has the definition of a function, and it can determine the compile-time value of the loop counter, then it has 100% of the information needed to unroll that loop.

How it gets this information is irrelevant. It could be an inline function (you have to provide the definition) which you call given a compile-time constant as an argument. It could be a constexpr function (again, you have to provide the definition) which you call given a compile-time constant as an argument.

This is a matter of quality of implementation, not of language. If compile-time parameters are to ever be a thing, it would be to support things you cannot do otherwise, not to support optimization (or at least, not compiler optimizations). For example, you can't have a function which returns a std::array whose length is specified by a regular function parameter rather than a template parameter.

like image 177
Nicol Bolas Avatar answered Jan 13 '23 17:01

Nicol Bolas


Yes you can, with std::integral_constant. Specifically, the following function will work with an int, as well as specializations of std::integral_constant.

template<class Num>
constexpr double do_it(Num m_unconverted) {
  double result = 0.;
  int m_converted = static_cast<int>(m_unconverted);
  for(int i = 0; i < m_converted; i++){ result += i; }
  return result;
}

If you want to call do_it with a compile-time constant, then you can use

constexpr double result = do_it(std::integral_constant<int, 5>{});

Otherwise, it's just

double result = do_it(some_number);
like image 28
hegel5000 Avatar answered Jan 13 '23 16:01

hegel5000