-2

I have a pretty simple code as the following.

template<typename T>
struct cell{
    int nr;
    T*  someInfo;
};

template<typename T>
void doSomething(cell<T> c)
{
    cout<<c.nr;
}

I actually have numerous functions using cells, very few using the T* template info (above code does not use it). Can I write my program (in C++98) without ending up with countless template keywords, T* or cell stuff? I want to reduce clutter, to write a rather C-like C++ code, easy to read by those who are not familiar with C++. Can I make the compiler understand (without macros) that whenever it sees cell, it is actually cell<T> and it has to put a template on the function?

If there is no C++98 solution, I prefer a C way using void* instead of T*. That comes with no clutter in the rest of the code, but I can't delete c.someInfo, but only free(c.someInfo).

Johan
  • 74,508
  • 24
  • 191
  • 319
Daniel Porumbel
  • 299
  • 2
  • 6
  • 1
    You might use inheritance, the non template part in the non template base. – Jarod42 Jan 17 '18 at 10:14
  • 5
    Why not just write good C code instead of bad C++ code? `new` and `delete` call `malloc` and `free` under the hood, so you're not really "gaining" anything. – user167921 Jan 17 '18 at 10:19
  • 1
    `easy to read by those who are not familiar with C++` My experience is that this is a bad idea. Not only do those not familiar with C++ learn about it as they read it, but the code ends up more complex than it needs to be so even those who ARE familiar with C++ end up getting confused. – UKMonkey Jan 17 '18 at 10:26
  • 4
    To paraphrase Mr. Miyagi: "Write C++, safe. Write C, safe. Write *C-like C++*, sooner or later, get stack smashed" – StoryTeller - Unslander Monica Jan 17 '18 at 10:28
  • Regarding the C-like C++, I only want WYSIWYG C++ where I have control over what happens when the code is executed. This is cited as an advantage of C over C++, as in the second point of [this answer](https://stackoverflow.com/a/20874130/7857819). See other reasons for C-like C++ in the [answer of user Solifugus](https://lwn.net/Articles/249460/) to the C++ criticisms of M. Torvalds. – Daniel Porumbel Jan 17 '18 at 11:16
  • @DanielPorumbel - What a load rubbish you linked to. You shouldn't even be considering templates if those are your guidelines. You want to write sub-par C++ by sticking to C-isms? By all means. Just be sure to point fingers at yourself when you start saying "C++ is a horrible language to use". – StoryTeller - Unslander Monica Jan 17 '18 at 11:46
  • @StoryTeller You have probably already used code written by some of those whose remarks you qualify as rubbish, maybe even on the device on which you read this message, assuming you do not use Windows exclusively. – Daniel Porumbel Mar 03 '18 at 08:08

5 Answers5

4

Reuse code by inheritance from a non-templated base class.

struct cell_base {
  int nr;
};

template<typename T>
struct cell : cell_base {
    T*  someInfo;
};

void doSomething(cell_base const& c)
{
    cout<<c.nr;
}

So whatever needs the non-templated bits accepts a cell_base, and the few things that do need the template parameter can be templates.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    Yes, that is a nice idea. Didn't think of that (despite doing it in a couple of places in my code, although not to save typing). – Bathsheba Jan 17 '18 at 10:15
  • Nice idea indeed. This can solve almost half of my problems. It is still possible to call `doSomething(..)` on a cell object. – Daniel Porumbel Jan 17 '18 at 11:33
2

If you want to use templates, then you need to use the correct template syntax.

Which does indeed mean writing T quite a few times as well as template<typename T>. That's life: the compiler does some very clever things, and needs this "boilerplate" in order to disambiguate.

You can reduce the amount of typing by writing all the functions inline inside the class declaration.

Using (void*) instead would be anachronistic.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

You can typedef your template; and which will completely hide the fact that it's a template for a specific type. ie

typedef cell<int> IntCell;

then usage of the type

void doSomething(const IntCell& c) {}
UKMonkey
  • 6,941
  • 3
  • 21
  • 30
  • Indeed, ok; but as you said, this works for a specific type. As long as I can not write `typedef cell TCell` this is not fully satisfactory. – Daniel Porumbel Jan 17 '18 at 10:47
  • @DanielPorumbel and I hope this explains why in the question you should say what you tried. There's nothing indicating that you couldn't there. – UKMonkey Jan 17 '18 at 11:10
0

Edit: I now realize that you asked about c++98. My suggestion requires c++14 unfortunately.

You could use generic lambdas in place of template functions:

auto doSomething = [](auto c) {
    cout<<c.nr;
}

If you're willing to wait for a bit, there is the concepts proposal for the C++ standard which will hopefully be included in C++20. It includes generic functions which could allow:

void doSomething(auto c)
{
    cout<<c.nr;
}

Or

void doSomething(Concept c)
{
    cout<<c.nr;
}

Where Concept is a concept that all cell<T> satisfy. This is a compile time analogue to the runtime inheritance suggested by StoryTeller.

eerorika
  • 232,697
  • 12
  • 197
  • 326
-1

Hoping this can be useful for somebody someday, I'll explain why I ended up with the old-school C solution in C++. You maybe need to be in the same mess as me to understand, i.e., you need to deal with some minor unknown pointer for which you do not want to clutter a C++ code which already has many classes that can not be ported to C in reasonable time. I thank all the responses I received, and after considering them, I regret they could not solve my problems. Even with inheritance, I still end up with hundreds of template and <T> stuff because I have many classes and sub-classes with cell members.

It is easier/cleaner to use void* someInfo as in C, as that does not require modifying all classes that contain cells. The problem of deleting the void* pointer is left to the user of the library. It's easy to allow/ask the user to make a unique call like set_func_free_info(&custom_free_func). The deallocation function of the library could be:

if(func_free_info!=NULL) 
    func_free_info(c.someInfo);
else                    //don't let it get here if someInfo points to an object
    free(c.someInfo);   //needing a destructor, do use set_func_free_info(...).

Given some of the responses, I feel you :

  • might argue void* is "anachronistic". Maybe. If somebody told me that such an old language like English is anachronistic faced to modern Esperanto, I would feel the same.
  • might say it is a bad idea to write code somehow for pure C programmers not familiar with C++, in the line with a above remark ``the code ends up more complex than it needs to be so even those who ARE familiar with C++ end up getting confused.''. If you honestly think about this, here the opposite is true : the code is less complex by avoiding C++ features, as the template constructs would clutter all the code for a minor feature.
  • ask why don't stick to pure C and simply finish the story. I can't, because this is part of a code where someInfo can be an object. So I end up with the C-like C++ style that some here seem to hate, but you can really find reasons for it on the linked material my comment above.

Anyway, M Stroustrup said that

C++ is deliberately designed to support a variety of styles rather than a would-be "one true way".

So if you like to lecture about "your true C++ way", you should understand you shouldn't do it. And you'll see life so much more than a foolish game. C++ supports infinitely many more styles and possibilities than C, e.g., I could use lambdas as in one of the replies, but too many would not understand it.

Daniel Porumbel
  • 299
  • 2
  • 6
  • Type-safety just went out the window. – Johan Jul 25 '22 at 13:32
  • I do not care, this is theory stuff, I like down-to-earth practicalities. Many libraries become slower and slower with each version because they never stop introducing features like thread-safety, type-safety, xxx-safety, each time sacrificing the speed (see also software bloat). – Daniel Porumbel Dec 30 '22 at 16:31