Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function calls in template arguments

Tags:

c++

gcc

I'm struggling with the following situation.

#include "systemc.h"

template<int maxval>
class Foo {
  /* Error: calls to constructors and functions cannot be part of a constant expression */
  sc_uint<int(log2(double(maxval)))> a;
  ...
};

int main() {

  Foo<10> foo;
  ...
  return 0;
}

As you can observe above, the templated class 'Foo' has the template parameter 'maxval'. 'Foo' also holds a member, again a templated class, that uses the template parameter 'maxval' together with the function 'log2' in its template arguments for instantiation. However, the depicted code will not work since e.g. function calls cannot be part of constant expressions. Do you see any possibility to evaluate e.g. log2(maxval) during compile time and to use the result for further template arguments inside 'Foo'?

Thanks for your help. (I'm using GCC 4.1.2)

like image 593
chessat2002 Avatar asked Feb 21 '26 05:02

chessat2002


1 Answers

Templates expect compile-time values. The log2 function would need to be constexpr for this to work (which it isn't).

You'd have to define your own constexpr function. In the case of a logarithm function to the base 2 it can work if you need an integer (cutting off the floating point part):

constexpr int log2(int number, int acc = 0) {
    return number <= 1 ? acc : log2(number / 2, acc + 1);
}

Edit:

I did not notice that the question asked for GCC 4.1, which does not support constexpr. While you should try to upgrade if that option is available to you, you can also go for a template-based solution, as proposed in @Florian's answer.

Edit 2:

In case you do not want to rely on Boost, here is a simple template-based implementation you could use:

template<int V>
struct log2 {
    static int const value = 1 + log2<V/2>::value;
};

template<>
struct log2<0> {};

template<>
struct log2<1> {
    static int const value = 0;
};

Then you'd use it as log2<13>::value, which would result in 3.

Yet another edit:

The constexpr implementation above will return 0 for 0 and negative numbers, which is a mistake. The logarithm is not defined for zero or negative values (in the real domain), so the function can be adjusted to throw an error (since it's getting a bit unreadable, I added some line breaks for formatting):

constexpr int log2(int number, int acc = 0) {
    return number <= 0
        ? throw std::logic_error{"Logarithm of zero or negative number not allowed."}
        : number == 1
            ? acc
            : log2(number / 2, acc + 1);
}
like image 165
Stjepan Bakrac Avatar answered Feb 22 '26 19:02

Stjepan Bakrac



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!