aboutsummaryrefslogtreecommitdiff
path: root/odb/details/function-wrapper.hxx
blob: 3a8ebfcd299adc9a4efc74f80cd0cb9301340cd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// file      : odb/details/function-wrapper.hxx
// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC
// license   : GNU GPL v2; see accompanying LICENSE file

#ifndef ODB_DETAILS_FUNCTION_WRAPPER_HXX
#define ODB_DETAILS_FUNCTION_WRAPPER_HXX

#include <odb/pre.hxx>

#include <odb/details/config.hxx> // ODB_CXX11

#ifdef ODB_CXX11
#  include <functional>  // std::function
#  include <type_traits> // std::enable_if, std::is_convertible
#endif

namespace odb
{
  namespace details
  {
    // Low-level 'callable object' wrapper similar to std::function but
    // that works in both C++98 and 11. In particular, the call site can
    // be compiled in C++98 and the registration site in C++11 and it
    // will work.
    //
    template <typename F>
    struct function_wrapper
    {
      ~function_wrapper ();

      explicit
      function_wrapper (F* = 0);

#ifdef ODB_CXX11
      typedef typename std::function<F> std_function_type;

      // This overload accepts lambdas and std::functions, but when the
      // argument is convertible to F*, then we disable it in favor of the
      // other overload (above), which is more efficient.
      //
      // Subtlety alert: if you're thinking of changing this to accept a
      // std::function<F> argument, stop. That creates an overload ambiguity
      // when the actual parameter is a lambda, which is convertible to either
      // std::function<F> or F*.
      //
      template <typename F1>
      function_wrapper(F1,
                       typename std::enable_if<
                       !std::is_convertible<F1, F*>::value>::type* = 0);
#endif

      // Destructive copy construction and assignment (aka move). These
      // should really only be called by containers when they need to
      // reallocate the underlying buffer and move the elements.
      //
      function_wrapper (const function_wrapper<F>&);
      function_wrapper&
      operator= (const function_wrapper<F>&);

      void swap (function_wrapper<F>&);

      // Conversion to bool.
      //
    public:
      typedef void (function_wrapper<F>::*bool_convertible) ();
      void true_value () {}

      operator bool_convertible () const
      {
        return function != 0 ? &function_wrapper<F>::true_value : 0;
      }

    public:
      F* function;
      void (*deleter) (const void*);
      const void* std_function;
    };
  }
}

#include <odb/details/function-wrapper.ixx>
#include <odb/details/function-wrapper.txx>

#include <odb/post.hxx>

#endif // ODB_DETAILS_FUNCTION_WRAPPER_HXX