0

I received a very large code, in which there is a class template <int dim> class point which works like a vector.

Since that class is involved (in a cascade manner) in many other classes, methods, etc., it forces those other classes, etc., to be templates with the same integral constant expression as a class template non-type argument. For instance, there is class D, to which I want to add:

  1. void D::coords(const point<dim>&).
  2. void D::verif(const source<dim>&).

Here source is a base class (could be abstract), with a huge hierarchy of its own, which uses point in one of its methods. In this case, I guess I am forced to convert D and all its derived hierarchy of classes to templates, which means modifying hundreds of sources/headers, at many points.

This addition would be much simpler if class point used dim as a class member instead of a template argument. I would simply add the method in D.h and D.cc. In all parts of the code that I saw, there is no occasion in which such change would not provide the same functionality.

Before I delve into the attempt to such huge modification, once and for all, I want to know...

What are possible uses of an integral constant expression as a class template non-type argument that are not replaceable by a class member? I guess there should be some, and I welcome all possible examples. This might help me understanding the options I have (perhaps none!)

Alternatively (option B?), Is there a way of making the intended additions, which does not require the huge modifications I foresee, but only the additions in D.h and D.cc?

  • You can use a specialization of `point` anywhere. Of course if someone wants to pass a specialization with a different template parameter, you're left with no options. Depending on what the `coords` function does you could make only the function a template, but you risk incompatibilities with member variables of course. – fabian Aug 07 '22 at 11:15
  • There are some scenarios where the change could actually result in different behavior instead of a compiler error, but those seem far-fetched for a "dimension" parameter. If `class point` is simple enough, you could reduce or eliminate chances of those by declaring all its function members `constexpr`. – aschepler Aug 07 '22 at 11:59
  • @fabian - You could post your comment as an answer. It might be a suitable workaround. – sancho.s ReinstateMonicaCellio Aug 07 '22 at 15:30

1 Answers1

2

What are possible uses of an integral constant expressions as a class template non-type argument that are not replaceable by a class member?

Any situation where such an expression must be compile-time evaluable. Many examples could be given, but a class with a std::array member of 'variant' size is one:

#include <iostream>
#include <array>
#include <algorithm>

template<size_t n>
class foo {
public:
    std::array<int, n> data;
    foo() {
        std::fill(data.begin(), data.end(), 42);
    }
    void list()
    {
        for (auto i : data) std::cout << i << " ";
        std::cout << std::endl;
    }
};

int main(void)
{
    foo<3> f3; f3.list();
    foo<7> f7; f7.list();
    return 0;
}

I'm not sure how foo could be implemented as a non-template class, even using constexpr qualifiers.

In fact, the std::array class template itself uses a non-type argument that is an "integral constant expression," so that is another example.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • Very good answer. There are uses of `std::array` in the code. From what I have just quickly checked, all its uses are replaceable by `std::vector` (and proper adjustments) with no big impact in overall performance stemming from what `array` is better than `vector` at. – sancho.s ReinstateMonicaCellio Aug 07 '22 at 11:44
  • ... bearing in mind the differences between `std::array` and `std::vector` (e.g., https://stackoverflow.com/questions/4424579/stdvector-versus-stdarray-in-c), if those are not an issue, your `data` could be changed to `std::vector` and `foo` is not a template anymore. – sancho.s ReinstateMonicaCellio Aug 07 '22 at 11:50
  • Indeed, changing from an `array` to a `vector` would be a potential solution in this case but, as your link points out, that may have undesirable consequences further down the road (such as losing the ability for compile-time evaluation of the size of a class object). – Adrian Mole Aug 07 '22 at 11:53
  • ... you can add the following line to the end of my `main` for a quick demo: `std::cout << sizeof(f3) << " " << sizeof(f7) << "\n";` – Adrian Mole Aug 07 '22 at 12:03