7

i've managed to create some preperty class with all the thing we expect from one. I mean when using it you don't need to call functions just using operator = will do all the work. but there is only one thing I guess it would be nice if we could resolve :

template <class T, class X,void (T::*setFunc)(const X&),const X& (T::*getFunc)()const> class property
{ 
    T* const owner;
    X data;
    friend T;
    property(T*const  pOwner) : owner (pOwner)
    {
    }
public:
    property& operator = (const X& input){(owner->*setFunc)(input);return *this;}
    operator const X&()const {return (owner->*getFunc)();}
};

struct c
{
protected:
    void setInt(const int& data);
    const int& getInt() const;
public:
    c();
    property<c, int ,&setInt,&getInt> myInt;
};

c::c() : myInt(this)
{
}

void c::setInt(const int& data)
{
    myInt.data = data;
}
const int& c::getInt() const
{
    return myInt.data;
}

see class property has 4 arguments and the first argument is the class type itself. I'd like to know if we could possibly do anything to extract class type from two function pointers property needs. somwthing like property <int, &setInt, &getInt> myInt;.

do you know any way to eliminate first template parameter?

Ali1S232
  • 3,373
  • 2
  • 27
  • 46
  • 3
    `friend T;` is technically valid only starting with C++0x. – Armen Tsirunyan Jul 04 '11 at 09:42
  • 24
    "temple of template". Are you a member of a C++ cult ? – slaphappy Jul 04 '11 at 09:44
  • 3
    The sample code will not work - you need to use &c::setInt and &c::getInt. – Karel Petranek Jul 04 '11 at 09:46
  • Could you add an example where using `property ` is better than `property `? – evnu Jul 04 '11 at 09:47
  • 2
    @evnu: I'm guessing it would be less typing and thus less error prone. – Nicol Bolas Jul 04 '11 at 09:54
  • @dark_charlie: it works, I've compiled that code on visual studio before submiting here. – Ali1S232 Jul 04 '11 at 10:00
  • @nicol-bolas: I am not sure if it is less typing, as long as he doesn't use instances of that property outside of the class itself (which would be useless if I am not mistaken). – evnu Jul 04 '11 at 10:00
  • @kbok: It seems more about a meta-form of C++, as I've personally only ever heard of C++ templates, but not about a templated C++. Not to mention it would be awesome to write Templated C++ Templates. – Sebastian Mach Jul 04 '11 at 10:01
  • @Gajet: Have you turned on all warnings? – Kerrek SB Jul 04 '11 at 10:05
  • @kerrekSB: first of all there is no warning and I'm compiling with /W4 flag, and it doesn't matter if there is warning or not, the only thing that matters is that the code runs flawless! – Ali1S232 Jul 04 '11 at 10:09
  • @Gajet: That might be a VS extension. Also it doesn't compile - the property does not have a parameterless constructor. Try to instantiate c and the build will fail. – Karel Petranek Jul 04 '11 at 10:14
  • @Gajet: Which version is your Visual C++? – Ise Wisteria Jul 04 '11 at 14:31
  • @dark charlie there is no problem with property not having a parameter less constructor, see my edit. – Ali1S232 Jul 04 '11 at 15:01
  • @lse visual studio express 2010 but i've done nothing illegal if there is some compiler that doesn't compile above code that's the compilers problem, (for the `&c::setInt` remember we are inside the class when defineing properties so it doesn't matter if you put `c::` or not) – Ali1S232 Jul 04 '11 at 15:03
  • @Gajet: Oh, I have no doubt of your code :-) I commented just because I thought of a way which is applicable only for VC10. – Ise Wisteria Jul 04 '11 at 15:53
  • @iseWsteria the second part was an answer to @dark_charlie. I didn't meant that way too. – Ali1S232 Jul 04 '11 at 15:57
  • @Gajet: That's not the compiler's problem. The C++ standard requires "A pointer to member is only formed when an explicit `&` is used and its operand is a *qualified-id* not enclosed in parentheses." Visual C++ unfortunately gets this wrong, and your code also is wrong. – Ben Voigt Jul 04 '11 at 16:58
  • @kbok: now I got what you ment, that was just a typeing error! – Ali1S232 Jul 05 '11 at 00:00

4 Answers4

4

If you'd like to omit specifying the type parameters explicitly, the following code will meet the purpose. However, this code requires VC2010.

template <class> struct class_type;
template <class C, class T> struct class_type< T(C::*) > { typedef C type; };

template <class> struct param_type;
template <class C, class T> struct param_type< void(C::*)(const T&) > {
    typedef T type;
};

template <class S, S setFunc, class G, G getFunc> struct property {
    typedef typename class_type<S>::type T;
    typedef typename param_type<S>::type X;
    T* const owner;
    X data;
    ....
};

#define PROPERTY(set, get) property<decltype(&set), &set, decltype(&get), &get>

struct c {
    void setInt(const int& data);
    const int& getInt() const;
    PROPERTY(setInt, getInt) myInt;
};

Incidentally, MSVC has its own property. Probably this is easier if it serves the purpose.

Ise Wisteria
  • 11,259
  • 2
  • 43
  • 26
  • Ok, that's a lot nicer than mine. +1. However, you do need `PROPERTY(c::setInt, c::getInt)` in order for it to be valid C++. – Ben Voigt Jul 04 '11 at 15:51
  • @BenVoigt: Oh, yes, the notation in the answer is applicable only for MSVC. Thank you for pointing out! – Ise Wisteria Jul 04 '11 at 16:30
  • your implementation seems to have some errors. and I can't figure out how to fix them. here is my code http://ideone.com/nPwZ5 and it's almost an exact copy/paste from here; – Ali1S232 Jul 04 '11 at 19:40
  • Here they are fixed on gcc: http://ideone.com/L3tgB On VC++ 2010 it runs into the same bug mine does, or so it would appear. – Ben Voigt Jul 04 '11 at 19:55
  • @Gajet @BenVoigt: I apologise for insufficient confirmation before posting the answer. Actually, I tested on VC2005 with Boost native typeof instead of `decltype`, and the code could be compiled in that environment. I'm sorry, if this doesn't work on VC2010. – Ise Wisteria Jul 04 '11 at 20:41
3

Success at last! http://ideone.com/XJ7of

This slightly better version works only on Comeau (not sure whether Comeau or gcc is correct, but gcc complains about the friend designation).

#include <iostream>
#include <typeinfo>

template <class T, class X,void (T::type::*setFunc)(const typename X::type&),const typename X::type& (T::type::*getFunc)()const> class property_impl
{ 
    typename T::type* const owner;
    friend typename T::type;
    property_impl(typename T::type* const pOwner) : owner (pOwner)
    {
    }
public:
    property_impl& operator = (const typename X::type& input){(owner->*setFunc)(input); return *this;}
    operator const typename X::type&()const {return (owner->*getFunc)();}
};

template<typename T> struct identity { typedef T type; };

template<typename Arg, typename T>
identity<T> match_memfn_classtype( void (T::*fn)(Arg) );

template<typename Arg, typename T>
identity<Arg> match_memfn_argtype( void (T::*fn)(Arg) );

#define property(setter,getter) property_impl<decltype(match_memfn_classtype(setter)), decltype(match_memfn_argtype(setter)), setter, getter>

struct C
{
private:
    int hiddenData;
protected:
    void setInt(const int& data) { hiddenData = data; std::cout << "setter used\n"; }
    const int& getInt() const { std::cout << "getter used\n"; return hiddenData; }
public:
    C() : myInt(this), hiddenData(5) {}
    property(&C::setInt,&C::getInt) myInt;
};

int main(void)
{
    C c;
    std::cout << "c.myInt = " << c.myInt << '\n';
    c.myInt = -1;
    std::cout << "c.myInt = " << c.myInt << '\n';
    return 0;
}

And VC++ 2010 chokes on all variations, although it does work for very simple use of match_memfn_classtype.

Bug report filed (please upvote):

C++ compiler loses member-ness of pointer-to-member-function during template deduction, causes ICE


Microsoft updated the bug report to say they've figured out a fix.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • it seems to fail on VC2010 express, but any how gave you an upvote! and the code you pasted here is not the one you submited to ideone. above code also fails to run on gcc so fix that! – Ali1S232 Jul 04 '11 at 19:45
  • @Gajet: It fails because of a bug in gcc, it seems. Eventually that bug will get fixed. In the meantime, you can download the version I put on ideone, which works on gcc. But @Ise's answer is better. – Ben Voigt Jul 04 '11 at 19:50
  • that has some problems both on my vc and on gcc (ideone) and i can't fix it :( – Ali1S232 Jul 04 '11 at 19:59
  • @Gajet: I fixed it on gcc: http://ideone.com/L3tgB but looks like it runs into the exact same MSVC bug mine does. – Ben Voigt Jul 04 '11 at 20:00
1

I'd like to know if we could possibly do anything to extract class type from two function pointers property needs.

Not really. There's no way to know what the class type of a member pointer is, even with metaprogramming type traits.

Oh, and those are member pointers, not function pointers. They're not the same thing.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I mean something like you declare a function `template swap(T& a, T& b)` and the you can use it without specifying T itself. – Ali1S232 Jul 04 '11 at 10:06
  • @Gajet: That's a function; it can infer the template parameters by the arguments you give it. You're making a class; you don't give a class arguments (you do the constructor, but that can't affect the class's type), so it can't infer anything. – Nicol Bolas Jul 04 '11 at 10:07
  • @Nicol: The class type of a pointer-to-member-function can be inferred, (the general case is probably difficult, the case here is easy). http://ideone.com/sPaWf However, getting that detected type back to the template argument list would be a cure worse than the disease. – Ben Voigt Jul 04 '11 at 14:46
  • The cure is pretty gnarly, but the final user-facing syntax is reasonably nice. – Ben Voigt Jul 04 '11 at 15:49
1

If removing template parameters is what you need, then you can do that, but not by removing the first template parameter. What you can do is remove the method pointer template parameters, because those are truly not needed. The code below compiled with gcc with no problems, it's a simplified version of you need but you can see what can be done with it:

template<class T, class X> class Foo {
public:
    typedef const X& (T::*GetterFunc)() const;
    typedef void (T::*SetterFunc)(const X&);
    Foo(T* instance, GetterFunc getter, SetterFunc setter):
        _owner(instance), _getter(getter), _setter(setter) { }

    T* _owner;
    GetterFunc _getter;
    SetterFunc _setter;

};

class FooBar {
};

class Bar {
public:
    Bar(FooBar& foobar):_foobar(foobar) { }
    const FooBar& get() const { return _foobar; }
    void set(const FooBar& foobar) { _foobar = foobar; }
    FooBar _foobar;
};


int main() {
    FooBar foobar;
    Bar bar(foobar);
    Foo<Bar, FooBar> foo(&bar, &Bar::get, &Bar::set);
    return 0;
}
Átila Neves
  • 1,351
  • 11
  • 14
  • The member function pointers are what you WANT to be template parameters, because that lets the compiler inline calls. – Ben Voigt Jul 04 '11 at 14:32
  • you got idea problem completely wrong i didn't want setter and getter not to be a part of template parameters, I wanted to eliminate T. – Ali1S232 Jul 04 '11 at 15:07