From ceff86b79401c27ed83cad65f59a6621c9a58084 Mon Sep 17 00:00:00 2001 From: Henrik Kinnunen Date: Fri, 19 Mar 2010 02:23:41 +0100 Subject: Added SelectArg and MemFunSelectArg* The MemFunSelectArg* functions can be used to select a specific argument from a signal. For example this would select the string argument as argument to the callback: Signal signal; signal.connect(MemFunSelectArg2(obj, &Object::takesOneStringArg)); signal.emit(10, 3.14, "hello"); ... void Object::takesOneStringArg(const string& value) { ... } --- src/FbTk/MemFun.hh | 56 ++++++++++++++++++++++++++++++++++++ src/FbTk/STLUtil.hh | 19 +++++++++++++ src/FbTk/SelectArg.hh | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/testSignals.cc | 33 ++++++++++++++++++++- 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/FbTk/SelectArg.hh diff --git a/src/FbTk/MemFun.hh b/src/FbTk/MemFun.hh index 0425fc6..d265703 100644 --- a/src/FbTk/MemFun.hh +++ b/src/FbTk/MemFun.hh @@ -22,6 +22,8 @@ #ifndef FBTK_MEM_FUN_HH #define FBTK_MEM_FUN_HH +#include "SelectArg.hh" + namespace FbTk { /// No argument functor @@ -218,6 +220,60 @@ MemFunIgnoreArgs( Object& obj, ReturnType (Object:: *action)(Arg1,Arg2) ) { return MemFun2IgnoreArgs(obj, action); } +/** + * Creates a functor that selects a specific argument of three possible ones + * and uses it for the single argument operator. + */ +template < int ArgNum, typename Functor> +class MemFunSelectArgImpl { +public: + + MemFunSelectArgImpl(Functor func): + m_func(func) { + } + + template + void operator ()(Type1 a, Type2 b, Type3 c) { + m_func(STLUtil::SelectArg()(a, b, c)); + } + + template + void operator ()(Type1 a, Type2 b) { + m_func(STLUtil::SelectArg()(a, b)); + } + + template + void operator ()(Type1 a) { + m_func(a); + } + +private: + Functor m_func; +}; + +/// Creates a functor that selects the first argument of three possible ones +/// and uses it for the single argument operator. +template +MemFunSelectArgImpl<0, MemFun1 > +MemFunSelectArg0(Object& obj, ReturnType (Object:: *action)(Arg1)) { + return MemFunSelectArgImpl<0, MemFun1 >(MemFun(obj, action)); +} + +/// Creates a functor that selects the second argument (or first if there is +/// only one) of three possible onesand uses it for the single argument operator. +template +MemFunSelectArgImpl<1, MemFun1 > +MemFunSelectArg1(Object& obj, ReturnType (Object:: *action)(Arg1)) { + return MemFunSelectArgImpl<1, MemFun1 >(MemFun(obj, action)); +} + +/// Creates a functor that selects the third argument (or the last argument if there is +/// less than three arguments) of three possible onesand uses it for the single argument operator. +template +MemFunSelectArgImpl<2, MemFun1 > +MemFunSelectArg2(Object& obj, ReturnType (Object:: *action)(Arg1)) { + return MemFunSelectArgImpl<2, MemFun1 >(MemFun(obj, action)); +} } // namespace FbTk diff --git a/src/FbTk/STLUtil.hh b/src/FbTk/STLUtil.hh index d427a17..e08036a 100644 --- a/src/FbTk/STLUtil.hh +++ b/src/FbTk/STLUtil.hh @@ -26,6 +26,25 @@ namespace FbTk { namespace STLUtil { +template +struct IfThenElse; + +template +struct IfThenElse { + Ta& operator ()(Ta& ta, Tb& tb) const { + return ta; + } + typedef Ta ResultType; +}; + +template +struct IfThenElse { + Tb& operator ()(Ta& ta, Tb& tb) const { + return tb; + } + typedef Tb ResultType; +}; + /// calls delete on each item in the container and then clears the container template void destroyAndClear(A &a) { diff --git a/src/FbTk/SelectArg.hh b/src/FbTk/SelectArg.hh new file mode 100644 index 0000000..83626ad --- /dev/null +++ b/src/FbTk/SelectArg.hh @@ -0,0 +1,74 @@ +// SelectArg.hh for FbTk +// Copyright (c) 2010 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef FBTK_STLUTIL_SELECT_ARG_HH +#define FBTK_STLUTIL_SELECT_ARG_HH + +#include "STLUtil.hh" + +namespace FbTk { + +namespace STLUtil { + +/** + * Selects a single argument from a maximum set of three arguments at compile time. + * For example: + * \begincode + * SelectArg<0>()( 10, 20, "hello" ); // returns first argument ( 10 ) + * SelectArg<1>()( 10, "hello", 30 ); // returns second argument ( "hello" ) + * SelectArg<2>()( 10, "hello", 30 ); // returns third argument ( 30 ) + * \endcode + * + * The selection of argument 1 and 2 can return the last argument if the + * arguments are less or equal to two. For instance: + * \begincode + * SelectArg<1>()(10); // returns 10 + * SelectArg<2>()(10, 20); // returns 20 + * SelectArg<2>()(10); // returns 10 + * \endcode + */ +template < int N > +struct SelectArg { + + template + typename IfThenElse::ResultType& operator ()(Type1& a, Type2& b){ + return IfThenElse()(a, b); + } + + template + typename IfThenElse::ResultType>::ResultType& + operator () (Type1& a, Type2& b, Type3& c) { + return IfThenElse::ResultType>() + (a, IfThenElse() (b, c) ); + } + + template < typename Type1 > + Type1 operator() (Type1 a) { + return a; + } +}; + +} // end namespace STLUtil +} // end namespace FbTk + +#endif // FBTK_STLUTIL_SELECT_ARG_HH diff --git a/src/tests/testSignals.cc b/src/tests/testSignals.cc index f382289..75f046e 100644 --- a/src/tests/testSignals.cc +++ b/src/tests/testSignals.cc @@ -49,7 +49,7 @@ struct FunctionClass { } void takeIt( string& str ) { - cout << "takeIt( " << str << ")" << endl; + cout << "FunctionClass::takeIt( " << str << " )" << endl; } void showMessage( int value, const string& message ) { @@ -61,8 +61,21 @@ struct FunctionClass { void threeArgs( int value, const string& str, double pi ) { cout << "(" << value << "): " << str << ", pi = " << pi << endl; } + }; +struct Printer { + void printInt(int value) { + cout << "Int:" << value << endl; + } + void printString(string value) { + cout << "string:" << value << endl; + } + void printFloat(float value) { + cout << "Float:" << value << endl; + } +}; + int main() { using FbTk::Signal; using FbTk::SignalTracker; @@ -161,4 +174,22 @@ int main() { // subject notify its observers source.emit("hello world"); } + + // Test argument selector + { + using namespace FbTk; + Signal source; + + Printer printer; + source.connect(MemFunSelectArg0(printer, &Printer::printInt)); + source.connect(MemFunSelectArg1(printer, &Printer::printString)); + source.connect(MemFunSelectArg2(printer, &Printer::printFloat)); + + source.emit(10, "hello", 3.141592); + + Signal source2; + source2.connect(MemFunSelectArg0(printer, &Printer::printString)); + source2.connect(MemFunSelectArg1(printer, &Printer::printInt)); + source2.emit("world", 37); + } } -- cgit v0.11.2