I'm trying to build a Graph Datastructure based on an already existing Datastructure (which I cannot modify and which is not a graph itself).
I think I have somewhat a grasp on how to build most of the structure concerning the graph itself, but right now I have to reference back to the original data structure for one little "compare" function and having a really hard time how to model that properly...
My vertices represent two different classes A and B of the original data structure, that have different member variables and no common ancestors. For an algorithm I have to check whether two vertices are compatible.
The rule is: an A-Vertex and an B-Vertex are always incompatible, but if both vertices represent the same type I have to check some specifics for the respective type.
So the base idea is roughly like this:
bool isCompatible(const Vertex& other){
// if this->data is of other type than other->data
// return false;
// else return compareFunction(this->data, other->data)
// where maybe one could overload that compare-function
// or make a template out of it
}
But I don't really know how to store the reference to data without making it really ugly.
Idea 1) Use a void pointer for data, have some variable to store the type and then cast the void pointer into respective type
-> would probably work but seems really dangerous (type-safety?) and really ugly (basically no reusability for the Graph structure if you ever wanna use it on other data). Seems a bit like the brute force approach.
Idea 2) Make an abstract data class that offers some "isCompatible(data)" function, and have wrapper-classes for A and B respectively that inherit from the abstract class and override that function. Inside the overridden function one could use dynamic_cast then and compare the objects.
-> still doesn't seem like good design, but should also work?
Idea 3) Make templates work? It's my first time working with C++ so I'm having a few problems wrapping my head around that properly.
I think something like the following should work for comparing:
template<typename T1, typename T2>
bool compare(T1 object1, T2 object2){
return false;
}
And then having instances for (A,A) and (B,B) that override this. For me this seems like the way to got for the comparison itself. But I don't really know how to manage the reference from Vertex to the Object without losing the Type. Any suggestions?
I'm open to any other suggestions as well of course.
edit: I'm using C++11 if that's of relevance.
If your data is either an A or a B, where those two types have nothing in common, then sounds like what you want is a variant data type. The C++ standard library doesn't have one yet, but you could use Boost's:
boost::variant<A, B> data;
A variant gives you type safety (which void* doesn't) and doesn't require you to have a common ancestor between the two types (which apparently are conceptually unrelated).
With a variant like the above, you can implement your comparison using binary visitation:
bool isCompatible(const Vertex& other) {
boost::apply_visitor(is_compatible(), data, other.data);
}
with:
class is_compatible
: public boost::static_visitor<bool>
{
public:
template <typename T, typename U>
bool operator()( const T &, const U & ) const
{
return false; // cannot compare different types
}
bool operator()( const A& lhs, const A& rhs ) const
{
// whatever A-specific comparison
}
bool operator()( const B& lhs, const B& rhs ) const
{
// whatever B-specific comparison
}
};
Related
I have many classes that use std::tie to make a tuple out of all the class attribute and use it to implement the == operator. They look like this:
class S
{
int number;
std::string text;
// and many other attributes...
auto tied() const noexcept { return std::tie(/* list all attributes here */); }
bool operator==(const S &o) const noexcept
{
return tied() == o.tied();
}
};
The classes have similar methods but very different attributes, so I want to create a base class they all inherit from and I want to include this bit of comparison in the base class.
However, since I can't define a virtual method returning auto, I'm struggling to write an abstract generic tied() method that should make a tuple out of all a derived class's attributes no matter how many of them or of which types they are.
Is this feasible?
Note: All attributes are either of trivial type or std::strings.
Is there a generic way to make a tuple out of all class attributes?
There is no way to generate a list of members. That is a language feature that requires more reflection capabilities than C++ has. At best you can have a macro that simultaneously generates the member declarations and the function generating the tuple. See Boost Fusion for an implementation of that idea.
Of course, you are not limited to the C pre processor for meta programming. You can use any langauge to generate C++ source if you don't mind complicating the build process.
I'm struggling to write an abstract generic tied()
There is no way to write a virtual member function that would return a different tuple for derived instances.
Is this feasible?
No.
and use it to implement the == operator.
Since C++20, you can use defaulted <=> to generate all comparison operators. Prior to that, you need the boilerplate.
If there is a bounded number of elements, you can use CRTP and https://stackoverflow.com/a/39779537/1774667 to find the number of elements.
Using structured binding you can then build a tuple out of them.
This can be written in the CRTP base.
template<class T>
struct implement_equals {
friend bool operator!=(implement_equals const& lhs, implement_equals const& rhs ) {
return !(lhs==rhs);
}
T const& self() const {
return *static_cast<T const*>(this);
}
friend bool operator==(implement_equals const& lhs, implement_equals const& rhs) {
constexpr std::size_t count = construct_airity<T>;
return make_tie_from<count>{}(lhs.self()) == make_tie_from<count>{}(rhs.self());
}
};
next write make_tuple_from.
template<std::size_t>
struct make_tie_from;
template<>
struct make_tie_from<1> {
template<class T>
auto operator()( T const& t ) const {
auto const&[e0] = t;
return std::tie(e0);
}
};
then write 20 of those.
There are libraries that do this already for you you can find with a bit of googling. None of them are perfect, and they all require that the thing you are making a tie of expose the data publicly.
If you want to hide that data, create a struct that contains the data publicly to get the tie, and expose some way for implement_equals to get access to that struct (friend, whatever).
In c++14 you cannot do even this crippled for of reflection.
You can write implement_equals, but you have to manually write the tie. It is better than a virtual function, however.
I have a data model that is quite large with many members, and many of them are themselves large data models, with nesting like this for several levels deep. The top class represents the overall model that is serialized and sent off to a server for backup. As a debugging step, we would like to deserialize a recent backup and compare it to the in-memory data model at the time of backup, which should be equal. The most obvious way to do this is apply operator== on the current model and its serialized-then-deserialized version.
The problem is that the degree of nesting and quantity of custom data structures will require a tremendous amount of code to write all those operator== implementations. Not to mention that many of those individual implementations will alone be many lines long to compare every member's equality. We're easily talking >1k lines of code just spent on operator==. Even if we do all that, there is large room for programmer error on something like this.
Is there any alternative for a quick and dirty (though reliable) equality check, perhaps using much lower level techniques, or anything that would not require a couple of days of doing nothing but writing operator== functions?
The tie solution is going to be your best bet.
struct equal_by_tie {
template<class T>
using enable = std::enable_if_t<std::is_base_of<equal_by_tie, T>,bool>;
template<class T>
friend enable<T>
operator==( T const& lhs, T const& rhs ) {
return mytie(lhs) == mytie(rhs);
}
template<class T>
friend enable<T>
operator!=( T const& lhs, T const& rhs ) {
return mytie(lhs) != mytie(rhs);
}
};
Now you have to write
struct some_thing : equal_by_tie {
public:
friend auto mytie( some_thing const& self ) {
return std::tie( self.x, self.y, self.mem3 );
}
};
and == and != are written for you.
There is currently no way to audit if mytie is written correctly, except with some hackery in C++17 that is honestly not worth considering (structured bindings, it is a horrible hack, don't ask).
One way you can reduce the chance that mytie is wrong is to use it more.
Implement swap in terms of it (maybe using the same parent class trick as operator== above). Now implement operator= in terms of swap or mytie. Do the same for friend std::size_t hash(Foo const&) and hook that into your standard hasher.
Insist that mytie be in the same order as your data declarations, and have it tie parent instances as sub-ties. Write a function that takes your system structure/class alignment into account and calculates how big the structure should be in a constexpr. Static assert that the sizes of Foo and calc_struct_size(tag<decltype(mytie(std::declval<Foo&>()))>) match. (Add in fudge factors for vtables or the like as required). Now changing the layout of the struct without touching mytie results in bad things happening.
Compare each pair of fields in mytie for pointer inequality to ensure you don't repeat the same field twice; try to ensure that this optimizes out to true at runtime (tricky, as you'll want to do this check in debug, and debug often has optimizations turned off; maybe this is a unique situation of an assert you want to execute only in release builds!).
You'll also want to do some sanity checks. If your mytie contains raw pointers, == is wrong, and same for smart pointers; you want your == to be a deep equality.
To that end, maybe == is the wrong thing.
struct deep_equal_by_tie {
template<class T>
using enable = std::enable_if_t<std::is_base_of<equal_by_tie, T>,bool>;
template<class T>
friend enable<T>
deep_equal( T const& lhs, T const& rhs ) {
// code to call deep_equal on each tie
// deep_equal on non-pointer basic types defined as ==
// deep_equal on pointers is to check for null (nulls are equal)
// then dereference and deep_equal
// ditto for smart pointers
// deep_equal on vectors and other std containers is to check size,
// and if matches deep_equal on elements
}
};
this, however, increases your load. But the idea is to increase reliability, as you have noted the hard part is that there is a lot of code and lots of spots to make mistakes.
There is no easy way to do this.
memcmp is a bad idea if your data is anything other than perfectly packed plain old data with no pointers or virtual functions or anything. And it is easy for padding to slip into code, breaking memcmp based equality; such braeks will be hard to find, as the state of data in the padding is undefined.
(Note: in case this feels like an X-Y problem, scroll below the separator for how I arrived at this question)
I am looking for a way to store pointers-to-member-functions (of different types) and compare them for equality. I need to store a mapping from pointer-to-member-function to an arbitrary object, and then search this mapping. It doesn't have to be an associative container, a linear search is fine. Also note that the pointers serve as mapping keys only, they are never dereferenced.
My current approach is this: when building the mapping, I reinterpret_cast the incoming pointer-to-member to one well-known type (void (MyClass::*)()) and insert it into the mapping. Something like this (error checking omitted for brevity):
template <class R, class... A)
void CallChecker::insert(R (MyClass::*key)(A...), Object value)
{
mapping.push_back(std::make_pair(reinterpret_cast<void (MyClass::*)()>(key), value));
}
Then on lookup, I perform the same cast and search by equality:
template <class R, class... A)
Object CallChecker::retrieve(R (MyClass::*key)(A...)) const
{
auto k = reinterpret_cast<void (MyClass::*)()>(key);
auto it = std::find_if(begin(mapping), end(mapping), [k](auto x) { return x.first == k; });
return it->second;
}
However, I am not sure that this will always work. While I believe it cannot produce false negatives (two equal pointers being reported as distinct), I am afraid it might produce false negatives (two pointers which were originally of different type could compare equal when cast to the "common" type). So my question is, is that the case? Or am I safe in using comparisons like this?
I know I am treading dangerously close to UB territory here. However, I don't mind a solution which works using behaviour which is not defined by the standard, but known to work in gcc and MSVC (my two target compilers).
So, the question is: is the comparison in a common type safe? Or would I be better off casting the stored pointer to the incoming type for the comparison (like this):
template <class R, class... A)
Object CallChecker::retrieve(R (MyClass::*key)(A...)) const
{
auto it = std::find_if(begin(mapping), end(mapping), [key](auto x) { return reinterpret_cast<R (MyClass::*)(A...)>(x.first) == key; });
return it->second;
}
Or will neither of these work in practice and I'm out of luck?
I am interested in the above properties of pointers-to-member, both in light of my actual task and to deepen my understanding of the language. Still, out of a sense of completeness (and in case somebody knows a better way), here is how I arrived at the original question.
I'm building a utility framework for helping unit-testing Qt4 signals (testing that the proper signals are emitted). My idea was to create a class CallChecker that would store validators (wrapped std::function objects) for slots, and be able to run them. The test would then create a class derived from this; that class would define slots which would run the corresponding validators. Here's an idea of usage (simplified):
class MyTester : public QObject, public CallChecker
{
Q_OBJECT
public slots:
void slot1(int i, char c) { CallChecker::checkCall(&MyTester::slot1, i, c); }
void slot2(bool b) { CallChecker::checkCall(&MyTester::slot2, b); }
};
void testRunner()
{
MyTester t;
connectToTestedSignals(t);
t.addCheck(&MyTester::slot1, [](int i, char c) { return i == 7; });
}
I have a working implementation (gcc on ideone) where CallChecker uses a std::vector of pairs, with the pointers-to-member cast to a common function type. After some fiddling with compiler flags (/vmg), I got this working in MSVC as well.
If you can suggest a better solution than lookup by pointer to member, I'll be happy to hear it. My goal is ease of use in the class implementing the test slots: I really want these slots to be simple one-liners. Using a textual representation of the slot signature (what Qt uses internally) is not really an option, as it's too susceptible to typos.
As I said in the comments, there is a way to unit test that a qt signal is emitted. You need to use QSignalSpy and link to QTestLib.
As they say in their documentation :
QSignalSpy can connect to any signal of any object and records its emission. QSignalSpy itself is a list of QVariant lists. Each emission of the signal will append one item to the list, containing the arguments of the signal.
You can also read their examples, but here is one of my unit tests that use google test :
class TestSomeControls : public testing::Test
{
public:
TestSomeControls() :
obj(),
ctrl1Dis( &obj, SIGNAL(DisableControl1(bool)) ),
ctrl2Dis( &obj, SIGNAL(DisableControl2(bool)) )
{
}
model::SomeControls obj;
QSignalSpy ctrl1Dis;
QSignalSpy ctrl2Dis;
};
TEST_F( TestSomeControls, OnControl1Clicked_untilControl1Disabled )
{
for ( int i = 0; i < 5; ++ i )
{
obj.OnControl1Clicked();
ASSERT_EQ( ctrl1Dis.count(), 0 );
}
obj.OnControl1Clicked();
ASSERT_EQ( ctrl1Dis.count(), 1 );
ASSERT_EQ( ctrl1Dis.takeFirst().at(0).toBool(), true );
}
Compare anything to anything.
#include <utility>
#include <memory>
#include <iostream>
struct Base
{
virtual bool operator== (const Base& other) const = 0;
virtual ~Base() {}
};
template <class T>
struct Holder : Base
{
Holder(T t) : t(t) {}
bool operator== (const Base& other) const
{
const Holder<T>* h = dynamic_cast<const Holder<T>*>(&other);
return (h && h->t == t);
}
private:
T t;
};
struct Any
{
template<class T>
Any(T t) : p(std::make_shared<Holder<T>>(t)) {}
bool operator== (const Any& other) const
{
return *p == *other.p;
}
private:
std::shared_ptr<Base> p;
};
int main ()
{
std::cout << (Any(2) == Any(2));
std::cout << (Any(2) == Any(3));
std::cout << (Any(2) == Any("foo"));
std::cout << (Any("foo") == Any("foo"));
std::cout << (Any("foo") == Any("bar"));
}
Implementation of operator< is deferred to the reader.
Important note Two pointers-to-member of different types will always compile unequal in this implementation, but it is possible that they will be equal in direct comparison after coercion to a common type. I.e &Foo::x and &Bar::x can be the same if Foo derives from Bar. Such behaviour cannot be easily added here.
If you first check that the typeid of both sides are the same, you can then use a type-erased function to cast both sides to the same type and compare in that type. (This is strictly necessary by the standard, as even if you can round-trip via a well-known type, there is no guarantee by the standard that comparisons in that type will have the same behaviour as comparisons in the original type.) Here's a sketch:
struct any_pmf_compare {
std::type_index ti;
void (any_pmf_compare::*pmf)();
bool (*comp)(const any_pmf_compare &, const any_pmf_compare &);
template<typename F>
any_pmf_compare(F f):
ti(typeid(F)),
pmf(reinterpret_cast<void (any_pmf_compare::*)()>(f)),
comp([](const any_pmf_compare &self, const any_pmf_compare &other) {
return reinterpret_cast<F>(self.pmf) == reinterpret_cast<F>(other.pmf);
})
{
}
};
bool operator==(const any_pmf_compare &lhs, const any_pmf_compare &rhs) {
return lhs.ti == rhs.ti && lhs.comp(lhs, rhs);
}
This is a narrow answer to the narrow question.
The standard states by implication and also in a footnote that a pointer to member cannot be converted to void*. The likely rationale is that a pointer to member could require more bytes of storage than a void*. Your compiler should forbid the reinterpret cast, and even it if does not you run a real risk of clashes. You can test on your target compilers, but the risk remains.
The standard will permit you to convert a 'pointer to member of X of type T1' to 'pointer to member of Y of type T2' when T1 and T2 are both function types. In other words, your strategy is permitted as long as the common type is a pointer to member function. I think this is what you intended. S5.2.10/10 in N3337. It does not however guarantee that two such pointers will compare equal, in the way that it does for pointers to objects. For example, if the implementation includes an encoded 'this' pointer, it just won't work.
The standard will permit you to store the pointer to member in a union. You can provide a char[] member that is likely to be long enough, and you can use an assert on sizeof to make sure that it is. Provided it's a 'standard layout' type, accessing the value through the char[] should have guaranteed behaviour. Personally, I would try this just to find out how big those pointers actually are! But the problem about possible non-canonical values remains.
My third suggestion is that you use the typeid of the pointer-to-member-function instead of the pointer itself. Typeid can be applied to any expression -- if it's good enough for reinterpret_cast it's good enough for typeid -- and the resultant value should be unique to the type, not the instance.
After that I'm out of ideas. You might have to redefine/renegotiate the problem in a quest for other solutions.
at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.
I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.
Here is my general idea of my class definition:
class object {
public:
int first;
string second;
object(int f, string s) {
first = f;
second = s;
}
bool operator<(const object &comp) {
return first < comp.first;
}
};
This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.
Here is a short code extract from my main function:
includes ...
//code omitted
int main() {
multiset<object*> mmset;
mmset.insert(new object(10, "test"));
mmset.insert(new object(11, "test"));
return 0;
}
After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.
code extract from the stl:
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.
I would really appreciate it if someone could help me.
Best Greetings
Tom
You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.
It seems like you really just want a multiset<object>:
multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");
Now it will use < to compare the objects themselves.
If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:
auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);
Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.
Thank you for your help. That's seems to be a good solution to solve this problem.
I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :)
I will post it just as information for other seekers with the same problem.
You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content.
The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.
class object {
int first;
string second;
object() { };
object(int f, string s) {
first = f;
second = s;
}
bool operator()(const object *comp1, const object *comp2) const {
return comp1->first < comp2->first;
}
}
The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:
multiset(object*, object) mmset;
You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.
I often find myself having to define two versions of a function in order to have one that is const and one which is non-const (often a getter, but not always). The two vary only by the fact that the input and output of one is const, while the input and output of the other is non-const. The guts of the function - the real work, is IDENTICAL.
Yet, for const-correctness, I need them both. As a simple practical example, take the following:
inline const ITEMIDLIST * GetNextItem(const ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<const ITEMIDLIST *>(reinterpret_cast<const BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
inline ITEMIDLIST * GetNextItem(ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<ITEMIDLIST *>(reinterpret_cast<BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
As you can see, they do the same thing. I can choose to define one in terms of the other using yet more casts, which is more appropriate if the guts - the actual work, is less trivial:
inline const ITEMIDLIST * GetNextItem(const ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<const ITEMIDLIST *>(reinterpret_cast<const BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
inline ITEMIDLIST * GetNextItem(ITEMIDLIST * pidl)
{
return const_cast<ITEMIDLIST *>(GetNextItem(const_cast<const ITEMIDLIST *>(pidl));
}
So, I find this terribly tedious and redundant. But if I wish to write const-correct code, then I either have to supply both of the above, or I have to litter my "consumer-code" with const-casts to get around the problems of having only defined one or the other.
Is there a better pattern for this? What is the "best" approach to this issue in your opinion:
providing two copies of a given function - the const and non-const versions
or just one version, and then requiring consumers of that code to do their casts as they will?
Or is there a better approach to the issue entirely?
Is there work being done on the language itself to mitigate or obviate this issue entirely?
And for bonus points:
do you find this to be an unfortunate by-product of the C++ const-system
or do you find this to be tantamount to touching the very heights of mount Olympus?
EDIT:
If I supply only the first - takes const returns const, then any consumer that needs to modify the returned item, or hand the returned item to another function that will modify it, must cast off the constness.
Similarly, if I supply only the second definition - takes non-const and returns non-const, then a consumer that has a const pidl must cast off the constness in order to use the above function, which honestly, doesn't modify the constness of the item itself.
Maybe more abstraction is desirable:
THING & Foo(THING & it);
const THING & Foo(const THING & it);
I would love to have a construct:
const_neutral THING & Foo(const_neutral THING & it);
I certainly could do something like:
THING & Foo(const THING & it);
But that's always rubbed me the wrong way. I am saying "I don't modify the contents of your THING, but I'm going to get rid of the constness that you entrusted me with silently for you in your code."
Now, a client, which has:
const THING & it = GetAConstThing();
...
ModifyAThing(Foo(it));
That's just wrong. GetAConstThing's contract with the caller is to give it a const reference. The caller is expected NOT TO MODIFY the thing - only use const-operations on it. Yes, the caller can be evil and wrong and cast away that constness of it, but that's just Evil(tm).
The crux of the matter, to me, is that Foo is const-neutral. It doesn't actually modify the thing its given, but its output needs to propagate the constness of its argument.
NOTE: edited a 2nd time for formatting.
IMO this is an unfortunate by-product of the const system, but it doesn't come up that often: only when functions or methods give out pointers/references to something (whether or not they modify something, a function can't hand out rights that it doesn't have or const-correctness would seriously break, so these overloads are unavoidable).
Normally, if these functions are just one short line, I'd just reduplicate them. If the implementation is more complicated, I've used templates to avoid code reduplication:
namespace
{
//here T is intended to be either [int] or [const int]
//basically you can also assert at compile-time
//whether the type is what it is supposed to be
template <class T>
T* do_foo(T* p)
{
return p; //suppose this is something more complicated than that
}
}
int* foo(int* p)
{
return do_foo(p);
}
const int* foo(const int* p)
{
return do_foo(p);
}
int main()
{
int* p = 0;
const int* q = foo(p); //non-const version
foo(q); //const version
}
The real problem here appears to be that you're providing the outside world with (relatively) direct access to the internals of your class. In a few cases (e.g., container classes) that can make sense, but in most it means you're providing low-level access to the internals as dumb data, where you should be looking at the higher-level operations that client code does with that data, and then provide those higher-level operations directly from your class.
Edit: While it's true that in this case, there's apparently no class involved, the basic idea remains the same. I don't think it's shirking the issue either -- I'm simply pointing out that while I agree that it is an issue, it's only that arises only rather infrequently.
I'm not sure low-level code justifies such things either. Most of my code is much lower level than most people ever have much reason to work with, and I still only encounter it rather infrequently.
Edit2: I should also mention that C++ 0x has a new definition of the auto keyword, along with a new keyword (decltype) that make a fair number of things like this considerably easier to handle. I haven't tried to implement this exact function with them, but this general kind of situation is the sort of thing for which they're intended (e.g., automatically figuring out a return type based on passed arguments). That said, they normally do just a bit more than you want, so they might be a bit clumsy (if useful at all) for this exact situation.
I don't believe it's the deficiency of const-correctness per se, but rather the lack of convenient ability to generalize a method over cv-qualifiers (in the same way we can generalize over types via templates). Hypothetically, imagine if you could write something like:
template<cvqual CV>
inline CV ITEMIDLIST* GetNextItem(CV ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<CV ITEMIDLIST *>(reinterpret_cast<CV BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
ITEMIDLIST o;
const ITEMIDLIST co;
ITEMIDLIST* po = GetNextItem(&o); // CV is deduced to be nothing
ITEMIDLIST* pco = GetNextItem(&co); // CV is deduced to be "const"
Now you can actually do this kind of thing with template metaprogramming, but this gets
messy real quick:
template<class T, class TProto>
struct make_same_cv_as {
typedef T result;
};
template<class T, class TProto>
struct make_same_cv_as<T, const TProto> {
typedef const T result;
};
template<class T, class TProto>
struct make_same_cv_as<T, volatile TProto> {
typedef volatile T result;
};
template<class T, class TProto>
struct make_same_cv_as<T, const volatile TProto> {
typedef const volatile T result;
};
template<class CV_ITEMIDLIST>
inline CV_ITEMIDLIST* GetNextItem(CV_ITEMIDLIST* pidl)
{
return pidl ? reinterpret_cast<CV_ITEMIDLIST*>(reinterpret_cast<typename make_same_cv_as<BYTE, CV_ITEMIDLIST>::result*>(pidl) + pidl->mkid.cb) : NULL;
}
The problem with the above is the usual problem with all templates - it'll let you pass object of any random type so long as it has the members with proper names, not just ITEMIDLIST. You can use various "static assert" implementations, of course, but that's also a hack in and of itself.
Alternatively, you can use the templated version to reuse the code inside your .cpp file, and then wrap it into a const/non-const pair and expose that in the header. That way, you pretty much only duplicate function signature.
Your functions are taking a pointer to a pidl which is either const or non-const. Either your function will be modifying the parameter or it won't - choose one and be done with it. If the function also modifies your object, make the function non-const. I don't see why you should need duplicate functions in your case.
You've got a few workarounds now...
Regarding best practices: Provide a const and a non-const versions. This is easiest to maintain and use (IMO). Provide them at the lowest levels so that it may propagate most easily. Don't make the clients cast, you're throwing implementation details, problems, and shortcomings on them. They should be able to use your classes without hacks.
I really don't know of an ideal solution... I think a keyword would ultimately be the easiest (I refuse to use a macro for it). If I need const and non-const versions (which is quite frequent), I just define it twice (as you do), and remember to keep them next to each other at all times.
I think it's hard to get around, if you look at something like vector in the STL, you have the same thing:
iterator begin() {
return (iterator(_Myfirst, this));
}
const_iterator begin() const {
return (iterator(_Myfirst, this));
}
/A.B.
During my work I developed a solution similar to what Pavel Minaev proposed. However I use it a bit differently and I think it makes the thing much simpler.
First of all you will need two meta-functions: an identity and const adding. Both can be taken from Boost if you use it (boost::mpl::identity from Boost.MPL and boost::add_const from Boost.TypeTraits). They are however (especially in this limited case) so trivial that they can be defined without referring to Boost.
EDIT: C++0x provides add_const (in type_traits header) meta-function so this solution just became a bit simpler. Visual C++ 2010 provides identity (in utility header) as well.
The definitions are following
template<typename T>
struct identity
{
typedef T type;
};
and
template<typename T>
struct add_const
{
typedef const T type;
};
Now having that generally you will provide a single implementation of a member function as a private (or protected if required somehow) static function which takes this as one of the parameters (in case of non-member function this is omitted).
That static function also has a template parameter being the meta-function for dealing with constness. Actual functions will the call this function specifying as the template argument either identity (non-const version) or add_const (const version).
Generally this will look like:
class MyClass
{
public:
Type1* fun(
Type2& arg)
{
return fun_impl<identity>(this, arg);
}
const Type1* fun(
const Type2& arg) const
{
return fun_impl<add_const>(this, arg);
}
private:
template<template<typename Type> class Constness>
static typename Constness<Type1>::type* fun_impl(
typename Constness<MyClass>::type* p_this,
typename Constness<Type2>::type& arg)
{
// Do the implementation using Constness each time constness
// of the type differs.
}
};
Note that this trick does not force you to have implementation in header file. Since fun_impl is private it should not be used outside of MyClass anyway. So you can move its definition to source file (leaving the declaration in the class to have access to class internals) and move fun definitions to source file as well.
This is only a bit more verbose however in case of longer non-trivial functions it pays off.
I think it is natural. After all you just said that you have to repeat the same algorithm (function implementation) for two different types (const one and non-const one). And that is what templates are for. For writing algorithms which work with any type satisfying some basic concepts.
I would posit that if you need to cast off the const of a variable to use it then your "consumer" code is not const correct. Can you provide a test case or two where you are running into this issue?
You don't need two versions in your case. A non-const thing will implicitly convert to a const thing, but not vice versa. From the name of you function, it looks like GetNextItem will have no reason to modify pidl, so you can rewrite it like this:
inline ITEMIDLIST * GetNextItem(const ITEMIDLIST * pidl);
Then clients can call it with a const or non-const ITEMIDLIST and it will just work:
ITEMIDLIST* item1;
const ITEMIDLIST* item2;
item1 = GetNextItem(item1);
item2 = GetNextItem(item2);
From your example, this sounds like a special case of having a pass-through function, where you want the return type to exactly match the parameter's type. One possibility would be to use a template. eg:
template<typename T> // T should be a (possibly const) ITEMIDLIST *
inline T GetNextItem(T pidl)
{
return pidl
? reinterpret_cast<T>(reinterpret_cast<const BYTE *>(pidl) + pidl->mkid.cb)
: NULL;
}
You could use templates.
template<typename T, typename U>
inline T* GetNextItem(T* pidl)
{
return pidl ? reinterpret_cast<T*>(reinterpret_cast<U*>(pidl) + pidl->mkid.cb) : NULL;
}
and use them like
ITEMDLIST* foo = GetNextItem<ITEMDLIST, BYTE>(bar);
const ITEMDLIST* constfoo = GetNextItem<const ITEMDLIST, const BYTE>(constbar);
or use some typedefs if you get fed up with typing.
If your function doesn't use a second type with the same changing constness, the compiler will deduce automatically which function to use and you can omit the template parameters.
But I think there may be a deeper problem hidden in the structure for ITEMDLIST. Is it possible to derive from ITEMDLIST? Almost forgot my win32 times... bad memories...
Edit: And you can, of course, always abuse the preprocessor. Thats what it's made for. Since you are already on win32, you can completly turn to the dark side, doesn't matter anymore ;-)