template class of derived class as parameter to function - dangers? - c++

EDIT: just to clarify, I understand why this code does not work,and I'm not attempting to fix it, but to understand what are the dangers if this code could compile without the semantic error.
I have found that the following code will cause a static semantic error.
I know that it's because std::list is a template class and that means that std::list<foo*> is a different type than std::list<bar*>
My question is, if the compiler would allow this type of conversion from std::list<bar*> to std::list<foo*> in the second call to print_all , what could be the danger?
I have searched around the site but couldn't find examples to bad things that could happen.
I have also tried to think of such examples but I'm not sure that these are correct or accurate.
(for example if the compiler would allow this, could I add a foo* object into the bar list in print_all() because it was converted to list?).
#include <list>
using std::list;
class foo {
// ...
};
class bar : public foo {
// ...
};
static void print_all(list<foo*>& L) {
// ...
}
list<foo*> LF;
list<bar*> LB;
// ...
print_all(LF); // works fine
print_all(LB); // static semantic error

list<foo*> and list<bar*> are two completely different classes, with no connection between them, other than beeing generated from the same template std::list (template<class T, class Allocator = std::allocator<T>> class list;). As such there isn't a conversion between them, unless the author of the template std::list explicitly wrote a conversion between std::list<T, A> and std::list<U, A> when T is a base class of U. And that is not written.
One way to achieve what you want is by creating template function:
template <class T, class A>
void print_all(std::list<T*, A>& l)
Now, there are a few caveats to be aware of:
I see no reason why you would make that static member. I would make it free function, but I would put it in a namespace with foo and bar
If you want to restrict it's usage strictly to foo and its derived classes you can do it with sfinae:
template <class T, class A, class E = std::enable_if_t<std::is_base_of_v<foo, T>>>
auto print_all(std::list<T*, A>& l)
{
}
And finally you should consider turning this into idiomatic C++ way of printing, aka streams and add the operator<<(std::ostream&, const std::list<T*, A>&) along with operator<<(std::ostream, const foo&) and maybe a virtual print function on foo. Here is extra important to define them in the same namespace as foo and bar.

You cannot use one vector instead of other because are different classes, but you can convert one vector to other implicitely or explicitely, using transformation or copy/ move constructors and assignment operator. It can cost you additional performance ( and memory in case of copy) overhead, but can be a deal in your particular case.

Related

Is std::iterator inherints from a sort of auto_ptr?

I am a beginner in STL. I'm trying to code a toystl to learn STL. When I code about iterator, I'm puzzled if I should code a simple auto_ptr first and inherint from it.
I wrote a base class called iterator. And now it works like this,
struct iterator{};
template <class T>
struct vector_itorater: public toystl::iterator<toystl::random_access_iterator_tag, T>{};
If i need another base class works like a "auto_ptr"? just like this
// firstly define a sort of auto_ptr as base class
struct auto_ptr{};
// secondly inherint from auto_ptr
template <class T>
struct vector_itorater: public auto_ptr{};
Does this work? Or does STL do it like this?
I think you mixed up runtime polymorphy and compile time polymorphy. When the compiler instantiates a template, it cares about its visible interface of the concrete object. It does not care if this object has a inheritance relationship with other classes, it will pass as long as the concrete object can be used within the concrete context.
template <class C>
void foo(const C& bar)
{
// at the time of writing we don't know anything of C,
// only that it has a callable baz member (either a
// member function or a member with a call operator).
// This works, since the compiler knows the exact type
// during template instantiation, but we don't have to
// care in advance.
bar.baz();
}
struct X
{
void baz() const;
};
void grml()
{
X x;
// The compiler fills in X as the template type
// parameter for us. So the compiler creates a
// void foo<X>(const X&) function for us.
foo(x);
}
In this example when the compiler sees the template, it has no clue how this template will be called later. Only once the template gets instantiated (used), the compiler then will check if the passed type is suitable for this template.
Here it is not needed to have a common base class to derive every possible implementation from. The STL uses templates in order to avoid to use such base classes, since they give you a burden on your design later, and if you have virtual members in the base to override, you can get a serious performance penalty.

Make a "typedef" be final (or simulate it)

Is it possible to mark an alias of a type as final (i.e. can't be re-defined in derived class)?
#include <iostream>
class B{
public: using type=std::string;
};
class D : public B{
public: using type=int; //<--- [1] I want a compile error here.
};
int main(){
typename D::type str="abc"; //<--- [2] This line is actually correct.
}
According to http://en.cppreference.com/w/cpp/language/final, it is for function only.
Is there a workaround?
It would be useful as a coder fool-proof in some cases.
No, you cannot.
Trait based types could do it, but the machinery is ugly.
Define a distributed type map maybe via an adl based tag function map.
template<class T>struct tag_t{constexpr tag_t(){} using type=T;};
template<class T>constexpr tag_t<T> tag{};
namespace trait {
template<class T>
constexpr void type_tag( tag_t<T> ){}
template<class T>
using type=typename decltype( type_tag( tag<T> ) )::type;
}
// non-final alias
struct A{
friend constexpr tag_t<int> type_tag(tag_t<A>){return {};}
};
// non-final alias
struct A{
friend constexpr tag_t<char> type_tag(tag_t<A>){return {};}
};
// final alias
struct B{
template<class T, std::enable_if_t< std::is_base_of<B,T>{}, bool> =true>
friend constexpr tag_t<std::string> type_tag(tag_t<T>){return {};}
};
now overriding A's type_tag works with trait::type<> but if you try the same with B you'll get a long incomprehensible error.
This is a bad plan.
Metaclasses will probably let you do something like this as well.
In general, both of these require writing a new sublanguage of C++ to enforce a constraint C++ does not enforce. Possible, but ill-advised unless you have an extemely good reason.
Tangential answer on how we could use enums or other dummies to usefully hide a type.
/*
* Imagine everybody uses managed strings in our project throughout,
* so everyone expects to be able to declare and print strings everywhere,
* especially for debugging...
*/
typedef OurInternalMangedStrings string;
/***/
void InternalStringManager::ReallyDoingNastyInternalStuff()
{
// Within this code casually using managed strings
// to format error messages, etc,
// would be fatal as it will cause nasty recursion.
enum DoNotUseStrings_DeadlockDanger { string, OurInternalMangedStrings };
printError(string ("I had an error here and I don't know why - code ") << errCode);
}
This will produce an error which will hopefully mention both string and DoNotUseStrings_DeadlockDanger, giving the clue.
But it is of limited use for types as while it stops the author from using the word "string", it doesn't stop the code from automatically performing conversion, or using objects of that type that already exist, eg the following will pass without comment if the constructor is not explicit:
printError("I had an error here and I don't know why at all!");
For data values I find it is more useful:
void MyManager::Setup()
{
{ SomeFeature newPimple = new Somefeature;
enum DoNotUseMember {someFeature};
/** set up newPimple using other member data and parameters
when it is ready I will assign it to the member variable "someFeature"
**/
/** any accidental use of a someFeature member will produce error message **/
// Ready to install the new pimpl as the visible feature
MUTEX_RAII(access_feature); // ... Or whatever might be needed
/* can still access someFeature by being explicit */
delete this->someFeature;
this->someFeature = newPimpl;
}
/** other setup code that uses the new feature **/
}
Personally, I would call the new instance someFeature and get the hiding behaviour for free, but many find the name reuse hard to read.
Another way I use this technique is in refactoring. I have a method that happily uses member values to control its behaviour, and then an enhancement is needed where one of the control values must be controlled externally. To implement this, the original no-argument method becomes a shim, calling a new method with the member as the argument.
But how to ensure the new method doesn't accidentally use the member instead of the argument? Personally, I'd make the argument mask the member, but we are again limited by the comprehension of others.

Refactoring out method common to all classes

I've got a global function that copies relevant bits of one object (or type Source) to another (of type Target), like so:
template<typename Source , typename Target>
void partialCopy( Source& source , Target& target )
{
// perform copy
}
The problem I find with global functions is that, unlike member functions, it is not instantly clear when coding which of the two arguments is the source and which is the target. Therefore I would like to have a member function partialCopy() in every class like so:
struct Foo
{
template<typename T>
void partialCopy( T& target )
{
::partialCopy( *this , target );
}
};
The problem now is that the member function has to be copied to dozens of classes. Is this a tolerable case of copy and paste programming? I've considered putting partialCopy in a header file partialCopy.h and using the preprocessor include to 'inject' it into each class, like so:
struct Foo
{
#include "partialCopy.h"
};
Foo f;
Bar b;
f.partialCopy( b );
Although this works I've never seen it done anywhere and don't know if its unacceptable.
I've already tried putting the partialCopy member function in a common base class and inheriting it but this doesn't work because the this keyword would then refer to the base class and not the derived class.
Is there an even better alternative? Please advise.
Edit
John's suggestion(in a thread that's been deleted) that I perform a static_cast to the derived class in a CRTP base class works nicely. #John please post this an answer and I will mark it as such.
I am posting this as an answer, because in my opinion it's appropriate. Henrik commented first, though. (However, this was also my first thought :))
const-reference
Use const& (const-reference) for source parameter. That way it's easily distinguishable from the target.
The added benefit is that it will verify and ensure const-correctness of your partial-copy function.
rvalue-reference
You might also think about overloading it for Source&&. If there are some buffers that are copied directly, your function might take use of it.
I would suggest overloading the stream operators for this.
E.g.
template<typename Source , typename Target>
void partialCopy(Source& source, Target& target)
{
// perform copy
}
effectively becomes:
template<typename Source , typename Target>
void operator>>(const Source& source, Target& target)
{
// perform copy
}
(also note that the Source parameter is now a const&, for clarity.
So you could simply write
Foo f;
Bar b;
f >> b;
Makes it much clearer what the source and target objects are.
I'm a bit late with this answer, but I thought you might be interested in a solution using CRTP as a clean alternative to copy-paste programming:
The problem now is that the member function has to be copied to dozens of classes. Is this a tolerable case of copy and paste programming? I've considered putting partialCopy in a header file partialCopy.h and using the preprocessor include to 'inject' it into each class [...].
Instead of copying or #including the code, consider the following:
// common code:
<template typename T>
class PartialCopyImplementer
{
public:
template<typename D>
void partialCopy(D& destination)
{
// ::partialCopy( *this , target );
}
};
// concrete implementations
class Foo1 : public PartialCopyImplementer<Foo1> // CRTP implementation
{
// ...
};
// concrete implementations
class Foo2 : public PartialCopyImplementer<Foo2> // CRTP ensures Foo1 and Foo2
// do not have a common base
{
// ...
};
The cleanest way would probably just be to leave partialCopy as a free function an use it that way. There is nothing inherently wrong with that, for example all the function in the standard libraries <algorithm> header are free function that will be used with objects.
It is also not really much clearer which of foo.partialCopy(bar) is the source and which the destination. Does partialCopy copy from or to bar? Generally it is useful to look at the documentation / function declaration in such cases. If you have clear names for the parameters and make them const when appropriat,e it should be pretty clear which way the objects get copied.
What about:
template<class T>
struct from_impl
{
T const& from;
from_impl(T const& f)
: from(f)
{}
};
template<class T>
from_impl<T> from(T const& f) {
return from_impl(f);
}
template<class T>
struct to_impl
{
T& to;
to_impl(T& t)
: to(t)
{}
};
template<class T>
to_impl<T> to(T& t) {
return to_impl(t);
}
template<class T>
void to(T const&); // prevent using with non-const values
template<class Source,class Target>
void partial_copy(from_impl<Source> source, to_impl<Target> target)
{
// use source.from and target.to to perform copy
}
// usage:
T1 object1;
T2 object2;
partial_copy(from(object1),to(object2));
This makes very clear what you want to do. from_impl and to_impl work like a kind of reference and from and to work as factory functions for easy usage. You could also try to implement something like.
partial_copy.from(Source).to(Target);
partial_copy(Source)->_(Target);
But normaly this is a lot of writing. Simply put partial_copy in its own namespace to prevent name clashes, let users make their own overload for customisation and use const& for signaling what source and destination are.

Inheritance and templates in C++

I have the following problem with inheritance and templates:
class Base {};
class Deriv : public Base {};
template <class T> class X{};
void f(X<Base>& inst) {}
int main()
{
X<Base> xb;
f(xb);
X<Deriv> xd;
f(xd);
return 0;
}
The program doesn't compile because there is not relation between X<Base> and X<Deriv>. Nevertheless I think it should be possible to do everything that can be done with X<Base> also with X<Deriv>. Is there anything that I could do other than copying the function body of f to a new function void g(X<Deriv>& inst)?
You could just continue using templates:
template<class T>
void f(X<T>& inst) {}
will work for both X<Base> and X<Derived>.
The compiler might duplicate the code (if it is not smart enough), but you don't have to.
Why do you think they should be related? Consider the following:
template<typename T>
class X;
template<>
class X<Base> {
int x;
};
template<>
class X<Deriv> {
double d;
};
They're definitely not interchangeable. So no, there is no relation between those classes and you can't pass one to a function expecting the other. You'll have to do something like make both types inherit from another common type that exposes the interface you need.
Regarding your comment, you can use type traits and static_assert to do what you would do in Java:
template<typename T>
void f(X<T>& inst) {
static_assert(std::is_base_of(Base, T)::value, "Template type must subclass Base");
// body of function...
}
If you need such functionality, then you must template on the type- or overload, as you have said. Alternatively, you might explicitly specialize X such that X<Derived> : X<Base>.
Different instantiations of a template are unrelated types, even if the instantiating template arguments are related. That is, X<A> is not related to X<B> regardless of what the relationship between A and B might be.
Now as of what can be done, it depends on what your template actually is. In some cases you can provide conversions so that the X<Derived> can be converted to a X<Base> for a particular operation. Another alternative is modifying your function to be able to take any X<T> for which T derives from Base (this can be done by creating a template and using SFINAE to disallow calling it with Ts that don't derive from Base. Again, depending on what your template is, you might be able to offer access to the underlying type, in which case the function could take a reference to Base (consider shared_ptr or unique_ptr with the .get() method)
Without a description of what you actually want to get done it is impossible to provide a good alternative.
It depends. Consider the case where X is std::shared_ptr. It would break type safety if std::shared_ptr<Derived> was derived from std::shared_ptr<Base>, but instead there is an implicit value conversion.
However, since you’re passing by reference to non-const, such a value conversion will not help you you directly.
Other possibilities include inheriting from a common interface, and templating your function.

errors porting C++ templates from GCC to Visual C++

The following compiles in GCC:
cvec.hpp:
template <class T>
class cvec : public deque<T>
{
class deque<T>::iterator Find(T);
};
cvec.cpp:
template <class T>
class deque<T>::iterator cvec<T>::Find(T element)
{
}
In Visual C++, get:
error C2242 "typedef name cannot follow class/struct/union.
I changed "class" in the header file to "typename", but receive error C3860 - template argument list must list parameters in the order used in the template param list. There is only one parameter in this case, T. Unless the compiler is confused about Find(T element)?
What is this supposed to mean in the header:
class deque<T>::iterator Find(T);
You are not declaring a class. The typename keyword would be valid here, but class makes no sense.
And the same is true in the .cpp file:
template <class T>
typename deque<T>::iterator cvec<T>::Find(T element)
is correct, class isn't.
Apart from this, it really looks like what you're trying to do is a horrible idea. std::deque already has a find function. It works. It is correct. It is efficient. There is no need to reinvent it.
The standard library containers are also not designed to be derived from. They don't have virtual destructors.
All you're achieving (apart from the compile errors) is that you're going to end up with a buggy, less efficient container class that'll confuse other C++ programmers because it doesn't use the idiomatic interface.
This should really be a comment, but I'm making it an answer so that I can format it for readability.
#jalf and #dvl -- As #dvl said above, none of the std containers have virtual destructors. Why does that matter?
Let's say you derive a class "X" from from std::deque.
class X : public std::deque<int>
{
// whatever ...
};
Let's now say that you have an "X" object, pointed to by a base pointer.
std::deque<int> *p = new X;
and you delete it
delete p;
The destructor for the derived class X will not be called, which can lead to lots of problems.
Your options:
1. Don't derive from std containers. Make them data members and write wrappers to expose the functionality.
2. Only derive from std containers if the derived class has no destructor and no data members with destructors.
3. If you derive from a std container, never refer to it by a base pointer.
After you create a class, it is sometimes hard to know how the class might be used in the future. For that reason, many developers stick strictly to option "1". Personally I permit deriving from a std container as long as it is well documented and used with care.
This works for me in 2010:
#include <deque>
template <class T>
class cvec : public std::deque<T>
{
public:
typedef typename std::deque<T>::iterator iterator;
iterator Find(T element);
};
template <class T>
typename cvec<T>::iterator cvec<T>::Find(T element)
{
return std::deque<T>::iterator();
}
using namespace std;
int main()
{
cvec<int> c;
c.Find(1);
return 0;
}