views:

214

answers:

2

Hi. Studing STL I have written a a simple program to test functors and modifiers. My question is about the difference aon using CLASS or STRUCT to write a functor and try to operate on it with function adaptors. As far as I understand in C++ the difference beetween CLASS and STRUCT is that in the last case the members are public by default. This is also what I read many times in the answers in this site. So please explain me why this short piece of code will fail to compile even if I declared all members ( just a function overloading () ) public when I try to use the not2 modifier. (I have not tried other modifiers e.g. binders yet)

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;

template <class T>
void print  (T  i) {
    cout << " " << i;
}
// In the manual I read:
// "In C++, a structure is the same as a class except that its members are public by default."
//  So if I declare all members public it should work....

template <class T>
class mystruct : binary_function<T ,T ,bool> {
    public :
    bool operator() (T  i,T  j) const { return i<j; }
};

template <class T>
class generatore 
{
public:
    generatore (T  start = 0, T  stp = 1) : current(start), step(stp)
    { }
    T  operator() () { return current+=step; }
private:
    T  current;
    T  step;
};

int main () {
    vector<int> first(10);
    generate(first.begin(), first.end(), generatore<int>(10,10) );
    first.resize(first.size()*2);
    generate(first.begin()+first.size()/2, first.end(), generatore<int>(1,17) );
    cout << "\nfirst :";
    for_each (first.begin(), first.end(), print<int>);
    cout << "\nFORWARD SORT :";
    sort(first.begin(),first.end(),mystruct<int>());       // OK ! even with CLASS
    for_each (first.begin(), first.end(), print<int>);
    sort(first.begin(),first.end(),not2(mystruct<int>())); // <--- THIS LINE WILL NOT COMPILE IF I USE CLASS INSTEAD OF STRUCT
    cout << "\nBACKWARD SORT :";
    for_each (first.begin(), first.end(), print<int>);
    cout << endl;
}

Everithing runs as expected if I use:

struct  mystruct : binary_function<T ,T ,bool> {
    public :
    bool operator() (T  i,T  j) const { return i<j; }
};

Part of the error message I obtain is:

g++ struct.cpp
/usr/include/c++/4.2.1/bits/stl_function.h:
In instantiation of ‘std::binary_negate >’:
struct.cpp:52: instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:116:
error: ‘typedef int std::binary_function::first_argument_type’ is inaccessible
/usr/include/c++/4.2.1/bits/stl_function.h:338:
error: within this context
/usr/include/c++/4.2.1/bits/stl_function.h:119:
error: ‘typedef int std::binary_function::second_argument_type’ is inaccessible ....

Seems that at least in this case a struct is not equivalent to a class with public members, but why ?

+8  A: 

The difference you read from other answers is correct. struct is just a class with public accessibility by default. This includes the inheritance modifier. Basically, you should mention public before the base class name when you're using a class to make those definitions equivalent:

template <class T>
class mystruct : public binary_function<T ,T ,bool> {
    public:
    bool operator() (T  i,T  j) const { return i<j; }
};

Otherwise, the compiler will assume that mystruct is privately inheriting binary_function<T,T,bool>.

You can verify this fact by changing the struct to:

struct  mystruct : private binary_function<T ,T ,bool> {
    public: // not required here
    bool operator() (T  i,T  j) const { return i<j; }
};

which is equivalent to your current definition of the class and see the compiler whine with a similar error message.

Mehrdad Afshari
Ok ! Now works. ! Thanks !
GBBL
+2  A: 

With structure the inheritance is public by default with class it's private by default (if you don't specify public/private/protected)

So:

class mystruct : binary_function

means

class mystruct : private binary_function

but

struct mystruct : binary_function

means

struct mystruct : public binary_function

For private inheritance the mystruct can use all the public stuff from binary_function but you can't call public method of binary_function on mystruct and mystruct is not of binary_function type (I believe).

So when you pass mystruct to where binary_function is expected, mystruct does not define stuff that is expected from binary_function.

More specifically, the functor is expected to have the following definitions that are provided by binary_function, so when you inherit from it you already have those declarations:

template <class _Arg1, class _Arg2, class _Result>
struct binary_function {
  typedef _Arg1 first_argument_type;   ///< the type of the first argument (no surprises here)
  typedef _Arg2 second_argument_type;  ///< the type of the second argument
  typedef _Result result_type;         ///< type of the return type
};
stefanB