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).
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.
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.
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) {}
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.
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.
Related
Sorry for the newbie question, but I have a feeling I am missing something here:
If I have a certain class template which looks like this (basically the only way to pass a lambda to a function in C++, unless I am mistaken):
template<typename V, typename F>
class Something
{
public:
int some_method(V val, F func) {
double intermediate = val.do_something();
return func(intermediate);
}
}
By reading the implementation of this class, I can see that the V class must implement double do_something(), and that F must be a function/functor with the signature int F(double).
However, in languages like Java or C#, the constraints for the generic parameters are explicitly stated in the generic class signature, so they are obvious without having to look at the source code, e.g.
class Something<V> where V : IDoesSomething // interface with the DoSomething() method
{
// func delegate signature is explicit
public int SomeMethod(V val, Func<double, int> func)
{
double intermediate = val.DoSomething();
return func(intermediate);
}
}
My question is: how do I know how to implement more complex input arguments in practice? Can this somehow be documented using code only, when writing a library with template classes in C++, or is the only way to parse the code manually and look for parameter usage?
(or third possibility, add methods to the class until the compiler stops failing)
C# and Java Generics have similar syntax and some common uses with C++ templates, but they are very different beasts.
Here is a good overview.
In C++, by default template checking was done by instantiation of code, and requrements are in documentation.
Note that much of the requirements of C++ templates is semantic not syntactic; iterators need not only have the proper operations, those operations need to have the proper meaning.
You can check syntactic properties of types in C++ templates. Off the top of my head, there are 6 basic ways.
You can have a traits class requirement, like std::iterator_traits.
You can do SFINAE, an accidentally Turing-complete template metaprogramming technique.
You can use concepts and/or requires clauses if your compiler is modern enough.
You can generate static_asserts to check properties
You can use traits ADL functions, like begin.
You can just duck type, and use it as if it had the properties you want. If it quacks like a duck, it is a duck.
All of these have pluses and minuses.
The downside to all of them is that they can be harder to set up than "this parameter must inherit from the type Foo". Concepts can handle that, only a bit more verbose than Java.
Java style type erasure can be dominated using C++ templates. std::function is an example of a duck typed type eraser that allows unrelated types to be stored as values; doing something as restricted as Java is rarely worthwhile, as the machinery to do it is harder than making something more powerful.
C# reification cannot be fully duplicated by C++, because C#'s runtime environment ships with a compiler, and can effectively compile a new type when you instantiate at runtime. I have seen people ship compilers with C++ programs, compile dynamic libraries, then load and execute them, but that isn't something I'd advise.
Using modern c++20, you can:
template<Number N>
struct Polynomial;
where Number is a concept which checks N (a type) against its properties. This is a bit like the Java signature stuff on steroids.
And by c++23 you'll be able to use compile time reflection to do things that make templates look like preprocessor macros.
In contrast with other languages, C++ classes cannot be extended once defined.
This is why free functions are preferable to member functions because these are more general way to extend the behavior of a class.
At the same time, the dot syntax (only used for member functions) can have some notational advantage, for example when there is an object that is "more important" than the rest of the arguments in a function call.
For example,
allocator a;
a.allocate(n); // vs. allocate(a, n);
This creates a tension in the language.
(A tension that in early C++ contributed to the creation of bloated classes.)
In the best case, the difference is syntactic.
In the worst case the desired syntax using dot forces the methods to be defined inside the class (with the risk of making the class to large by including a lot of member functions).
This is what C++ is so far, and we are used to live with this.
However there is, for some cases a loop hole.
The question is whether this loop hole is frequently exploited or if it can create problems down the road.
The fact is that one can emulate extensions of a class by leaving template member function open.
For example:
struct A{
void f(int n) const{...}
void g(std::string s) const{...};
};
The "member" g cannot be extended to make this work A a; a.g(42).
However one can do this to make the syntax work:
struct A{
void f(int n) const{}
template<class T> void g(T t) const; // this can be even customized by a user of the library
};
// this can be defined anywhere down the road (but before `A::g<T>` is instantiated I think).
template<> void A::g<int>(int t) const{}
template<> void A::g<std::string>(std::string t) const{}
The extension is not general, any extension will have to have a fixed name (and one parameter) in this case but it feels like an extension nevertheless.
Besides the ugly out of class template code, is there any problem in using this technique to extend classes?
It is not straightforward in the general case but the technique can be even extended to customize different return types I think (here I used void for simplicity, another simple cases is when the return type is T itself also).
A problem I can see is that partial specialization is probably very difficult.
Another one is that order of instantiation can be problematic, the customizations need to be defined before first use (?).
Customizing a named function is not very impressive.
But other functions like template<class T> operator=(T const); can be customized. Effectively, this is like overloading assignment from outside the class which is not possible by normal means.
Besides the ugly out of class template code, is there any problem in using this technique to extend classes?
No, it is called "member templates" and it is a perfectly valid thing in C++.
Update:
I know it is valid. I am wondering if this is a technique frequently used.
I've personally never used it that often. Usually, have been deciding to implement the whole class as a template rather than focusing on individual functions. Yet at the same time I believe this sort of things depend on what you are trying to achieve and what is your personal taste. I mean it is a feature of the language and so why not use it whenever it feels like it would suit.
In page 671 of his new book Mr Stroustrup wrote the following sentence:
Note that there is no requirement that different arguments for the
same template parameter should be related by inheritance.
I can understand what the author wrote, but I can't understand the reason why he inserted this comment in the text. I think I'm missing something here, but I don't know exactly what.
When introducing the concept of templates, he tries to make clear that its not some kind of polymoprhism.
Before template were invented and added to C++ you could write generic code only using inheritance (or multilple inheritance).
Another concept that Mr.Stroustrup certainly want the reader not to confuse with templates is interfaces. In the java comunity for example this is a very popular technique and many books abot OOP explain this concept. Interfaces allow you to use some kind of generic code with a class, at the condition that the class is defined to implement (not inherit) a specific interface. All classes using the interface must be related to it. It's not strictly speaking inheritance, but it's a kind of substitute to multiple inheritance.
Templates can be used with any object or class without its type being related in advance to anything in common.
The answer is simple if we look at the use case of templates from the perspective of someone who is totally new to the concept of templates.
int i;
double d;
char c;
print(&i); //prints an integer
print(&d); //prints a double
print(&c); //prints a char
From the perspective of someone who does not understand C++ templates, he/she would assume that the prototype of print looks something like this.
print(SomeBaseType* pdata);
OR
print(void* pdata);
However, what happens with templates is with a function template such as
template <typename T>
print(T* pdata);
for the above use case, the compiler generates three functions during compile-time
print(int* pdata);
print(double* pdata);
print(char* pdata);
and through function overload resolution, the right function gets called.
Thank you for reading.
Disclaimer: A print function might not be the best example.
What is exactly new in c++ concepts? In my understanding they are functionally equal to using static_assert, but in a 'nice' manner meaning that compiler errors will be more readable (as Bjarne Stroustup said you won't get 10 pages or erros, but just one).
Basically, is it true that everything you can do with concepts you can also achieve using static_assert?
Is there something I am missing?
tl;dr
Compared to static_asserts, concepts are more powerful because:
they give you good diagnostic that you wouldn't easily achieve with static_asserts
they let you easily overload template functions without std::enable_if (that is impossible only with static_asserts)
they let you define static interfaces and reuse them without losing diagnostic (there would be the need for multiple static_asserts in each function)
they let you express your intents better and improve readability (which is a big issue with templates)
This can ease the worlds of:
templates
static polymorphism
overloading
and be the building block for interesting paradigms.
What are concepts?
Concepts express "classes" (not in the C++ term, but rather as a "group") of types that satisfy certain requirements. As an example you can see that the Swappable concept express the set of types that:
allows calls to std::swap
And you can easily see that, for example, std::string, std::vector, std::deque, int etc... satisfy this requirement and can therefore be used interchangeably in a function like:
template<typename Swappable>
void func(const Swappable& a, const Swappable& b) {
std::swap(a, b);
}
Concepts always existed in C++, the actual feature that will be added in the (possibly near) future will just allow you to express and enforce them in the language.
Better diagnostic
As far as better diagnostic goes, we will just have to trust the committee for now. But the output they "guarantee":
error: no matching function for call to 'sort(list<int>&)'
sort(l);
^
note: template constraints not satisfied because
note: `T' is not a/an `Sortable' type [with T = list<int>] since
note: `declval<T>()[n]' is not valid syntax
is very promising.
It's true that you can achieve a similar output using static_asserts but that would require different static_asserts per function and that could get tedious very fast.
As an example, imagine you have to enforce the amount of requirements given by the Container concept in 2 functions taking a template parameter; you would need to replicate them in both functions:
template<typename C>
void func_a(...) {
static_assert(...);
static_assert(...);
// ...
}
template<typename C>
void func_b(...) {
static_assert(...);
static_assert(...);
// ...
}
Otherwise you would loose the ability to distinguish which requirement was not satisfied.
With concepts instead, you can just define the concept and enforce it by simply writing:
template<Container C>
void func_a(...);
template<Container C>
void func_b(...);
Concepts overloading
Another great feature that is introduced is the ability to overload template functions on template constraints. Yes, this is also possible with std::enable_if, but we all know how ugly that can become.
As an example you could have a function that works on Containers and overload it with a version that happens to work better with SequenceContainers:
template<Container C>
int func(C& c);
template<SequenceContainer C>
int func(C& c);
The alternative, without concepts, would be this:
template<typename T>
std::enable_if<
Container<T>::value,
int
> func(T& c);
template<typename T>
std::enable_if<
SequenceContainer<T>::value,
int
> func(T& c);
Definitely uglier and possibly more error prone.
Cleaner syntax
As you have seen in the examples above the syntax is definitely cleaner and more intuitive with concepts. This can reduce the amount of code required to express constraints and can improve readability.
As seen before you can actually get to an acceptable level with something like:
static_assert(Concept<T>::value);
but at that point you would loose the great diagnostic of different static_assert. With concepts you don't need this tradeoff.
Static polymorphism
And finally concepts have interesting similarities to other functional paradigms like type classes in Haskell. For example they can be used to define static interfaces.
For example, let's consider the classical approach for an (infamous) game object interface:
struct Object {
// …
virtual update() = 0;
virtual draw() = 0;
virtual ~Object();
};
Then, assuming you have a polymorphic std::vector of derived objects you can do:
for (auto& o : objects) {
o.update();
o.draw();
}
Great, but unless you want to use multiple inheritance or entity-component-based systems, you are pretty much stuck with only one possible interface per class.
But if you actually want static polymorphism (polymorphism that is not that dynamic after all) you could define an Object concept that requires update and draw member functions (and possibly others).
At that point you can just create a free function:
template<Object O>
void process(O& o) {
o.update();
o.draw();
}
And after that you could define another interface for your game objects with other requirements. The beauty of this approach is that you can develop as many interfaces as you want without
modifying your classes
require a base class
And they are all checked and enforced at compile time.
This is just a stupid example (and a very simplistic one), but concepts really open up a whole new world for templates in C++.
If you want more informations you can read this nice article on C++ concepts vs Haskell type classes.
Disclaimer: the question is completely different from Inheritance instead of typedef and I could not find any similar question so far
I like to play with c++ template meta-programming (at home mostly, I sometimes introduce it lightly at work but I don't want to the program to become only readable to anyone who did not bother learning about it), however I have been quite put out by the compiler errors whenever something goes wrong.
The problem is that of course c++ template meta-programming is based on template, and therefore anytime you get a compiler error within a deeply nested template structure, you've got to dig your way in a 10-lines error message. I have even taken the habit of copy/pasting the message in a text-editor and then indent the message to get some structure until I get an idea of what is actually happening, which adds some work to tracking the error itself.
As far as I know, the problem is mostly due to the compiler and how it output typedefs (there are other problems like the depth of nesting, but then it's not really the compiler fault). Cool features like variadic templates or type deduction (auto) are announced for the upcoming C++0x but I would really like to have better error messages to boot. It can prove painful to use template meta-programming, and I do wonder what this will become when more people actually get into them.
I have replaced some of the typedefs in my code, and use inheritance instead.
typedef partition<AnyType> MyArg;
struct MyArg2: partition<AnyType> {};
That's not much more characters to type, and this is not less readable in my opinion. In fact it might even be more readable, since it guarantees that the new type declared appears close to the left margin, instead of being at an undetermined offset to the right.
This however involves another problem. In order to make sure that I didn't do anything stupid, I often wrote my templates functions / classes like so:
template <class T> T& get(partition<T>&);
This way I was sure that it can only be invoked for a suitable object.
Especially when overloading operators such as operator+ you need some way to narrow down the scope of your operators, or run the risk of it been invoked for int's for example.
However, if this works with a typedef'ed type, since it is only an alias. It sure does not work with inheritance...
For functions, one can simply use the CRTP
template <class Derived, class T> partition;
template <class Derived, class T> T& get(partition<Derived,T>&);
This allows to know the 'real' type that was used to invoke the method before the compiler used the public inheritance. One should note that this decrease the chances this particular function has to be invoked since the compiler has to perform a transformation, but I never noticed any problem so far.
Another solution to this problem is adding a 'tag' property to my types, to distinguish them from one another, and then count on SFINAE.
struct partition_tag {};
template <class T> struct partition { typedef partition_tag tag; ... };
template <class T>
typename boost::enable_if<
boost::same_type<
typename T::tag,
partition_tag
>,
T&
>::type
get(T&)
{
...
}
It requires some more typing though, especially if one declares and defines the function / method at different places (and if I don't bother my interface is pretty soon jumbled). However when it comes to classes, since no transformation of types is performed, it does get more complicated:
template <class T>
class MyClass { /* stuff */ };
// Use of boost::enable_if
template <class T, class Enable = void>
class MyClass { /* empty */ };
template <class T>
class MyClass <
T,
boost::enable_if<
boost::same_type<
typename T::tag,
partition_tag
>
>
>
{
/* useful stuff here */
};
// OR use of the static assert
template <class T>
class MyClass
{
BOOST_STATIC_ASSERT((/*this comparison of tags...*/));
};
I tend to use more the 'static assert' that the 'enable_if', I think it is much more readable when I come back after some time.
Well, basically I have not made my mind yet and I am still experimenting between the different technics exposed here.
Do you use typedefs or inheritance ?
How do you restrict the scope of your methods / functions or otherwise control the type of the arguments provided to them (and for classes) ?
And of course, I'd like more that personal preferences if possible. If there is a sound reason to use a particular technic, I'd rather know about it!
EDIT:
I was browsing stackoverflow and just found this perl from Boost.MPL I had completely forgotten:
BOOST_MPL_ASSERT_MSG
The idea is that you give the macro 3 arguments:
The condition to check
a message (C++ identifier) that should be used for display in the error message
the list of types involved (as a tuple)
It may help considerably in both code self documentation and better error output.
What you are trying to do is to explicitly check whether types passed as template arguments provide the concepts necessary. Short of the concept feature, which was thrown out of C++0X (and thus being one of the main culprits for it becoming C++1X) it's certainly hard to do proper concept checking. Since the 90ies there have been several attempts to create concept-checking libraries without language support, but, basically, all these have achieved is to show that, in order to do it right, concepts need to become a feature of the core language, rather than a library-only feature.
I don't find your ideas of deriving instead of typedef and using enable_if very appealing. As you have said yourself, it often obscures the actual code only for the sake of better compiler error messages.
I find the static assert a lot better. It doesn't require changing the actual code, we all are used to having assertion checks in algorithms and learned to mentally skip over them if we want to understand the actual algorithms, it might produce better error messages, and it will carry over to C++1X better, which is going to have a static_assert (completely with class designer-provided error messages) built in into the language. (I suspect BOOST_STATIC_ASSERT to simply use the built-in static_assert if that's available.)