On 07/29/2016 12:29 PM, Alex Rousskov wrote:

> If possible, we should avoid macros and should learn how to use C++11
> correctly. In general, it makes little sense to suffer the pains of
> switching to C++11 and then use macros for things C++11 is supposed to
> provide or support natively.
> 
> However, in this specific case, some macros may be unavoidable or even a
> good idea because we are also dealing with C libraries that we cannot
> convert to C++11. Please give me a few hours to think whether there is a
> macro-free solution available.


I found two macro-free ways to do this. The so called "smart" one does
most of the work for us, but requires repeating the function name twice,
once with decltype() and once without:

    typedef HardFun<decltype(BIO_vfree), &BIO_vfree> BIO_Deleter;

A simpler implementation is arguably more verbose/repetitive:

    typedef HardFun<void, BIO*, &BIO_vfree> BIO_Deleter;

For comparison, the macro-based approach yields:

    CtoDeleter(BIO, BIO_vfree); // declares BIO_Deleter

And the current buggy trunk code is equivalent to this perfection:

    typedef std::function<decltype(BIO_free)> BIO_Deleter;


Since the smarter implementation does not give a perfect result despite
its tricks/complexity, I suggest going with the simpler one. The macros
do not seem to be necessary (and HardFun offers better reuse
possibilities than a macro if we need more hard-coded functors).

I have attached sketches for the smart and simple implementation. They
compile and run without throwing, but I have not tested beyond that (but
the same kind of sketch with the trunk-equivalent code did throw).


HTH,

Alex.

#include <functional>
#include <memory>

/* for testing without OpenSSL */
struct BIO {};
extern "C" { void BIO_vfree(BIO *bio) { delete bio; } };


/* for extracting result and argument types from a unary function type */
template <typename T>
struct function_traits;
template <typename ReturnType, typename ArgType>
struct function_traits<ReturnType(ArgType)>
{
    typedef ReturnType result_type;
    typedef ArgType arg_type;
};


/* a functor that calls a hard-coded unary function */
template <class FunType, FunType *fun>
struct HardFun {
    typename function_traits<FunType>::result_type
    operator()(typename function_traits<FunType>::arg_type arg) { fun(arg); }
};


/* usage example */

typedef HardFun<decltype(BIO_vfree), &BIO_vfree> BIO_Deleter;
typedef std::unique_ptr<BIO, BIO_Deleter> BIO_Pointer;

int main() {
    BIO_Pointer bio(new BIO);
    return 0;
}
#include <functional>
#include <memory>

/* for testing without OpenSSL */
struct BIO {};
extern "C" { void BIO_vfree(BIO *bio) { delete bio; } };


/* a functor that calls a hard-coded unary function */
template <class ReturnType, class ArgType, ReturnType (*fun)(ArgType)>
struct HardFun {
    ReturnType operator()(ArgType arg) { fun(arg); }
};

/* usage example */

typedef HardFun<void, BIO*, &BIO_vfree> BIO_Deleter;
typedef std::unique_ptr<BIO, BIO_Deleter> BIO_Pointer;

int main() {
    BIO_Pointer bio(new BIO);
    return 0;
}
_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev

Reply via email to