Version 1 is in SWI-cpp.h
; version 2 is in SWI-cpp2.h
,
SWI-cpp2.cpp
, SWI-cpp2-plx.h
, and SWI-cpp2-atommap.h
.
The overall structure of the API has been retained - that is, it is a
thin layer on top of the interface provided by
SWI-Prolog.h
. Based on experience with the API, most of the
conversion operators and some of the comparison operators have been
removed or deprecated, and replaced by "getter" methods; the overloaded
constructors have been replaced by subclasses for the various types.
Some changes were also made to ensure that the
operator for []
PlTerm
and PlTermv
doesn't cause unexpected implicit conversions.
2If there is an implicit
conversion operator from PlTerm
to term_t
and
also to char*
, then the
operator is ambiguous if []
f
is overloaded to accept a term_t
or char*
in the code PlTerm t=...; f(t[0])
Prolog exceptions are now converted to C++ exceptions (which contain
the exception term rather being a subclass of PlTerm
as in
version 1), where they can be caught and thrown using the usual C++
mechanisms; and the subclasses that create exceptions have been changed
to functions. In addition, an exception type PlFail
has
been added, together with PlCheckFail(), to allow more compact code by
"short circuit" return to Prolog on failure.
A convenience class for creating blobs has been added, so that an existing structure can be converted to a blob with only a few lines of code.
More specifically:
SWI-cpp2.cpp
has been added, containing the
implementation of some functions. This is included by default from SWI-cpp2.h
or can be compiled separately.SWI-Prolog.h
, and have the same names with the “PL''
replaced by “Plx''.3 “Pl''
is used throughout the SWI-cpp2.h
interface, and the “x''
is for “eXtended with eXception handling.'' Where
appropriate, these check return codes and throw a C++ exception (created
from the Prolog error). See section
2.5.4. Many of these wrapper functions are also methods in the PlAtom
and PlTerm
classes, with the arguments changed from
atom_t
and term_t
to PlAtom
and PlTerm
.
These wrappers are available if you include SWI-cpp2.h
(they are in a separate SWI-cpp2-plx.h
file for ease of
maintenance).false
from a foreign predicate to
indicate failure, you can use throw PlFail()
. The
convenience function PlCheckFail(rc) can be used to throw PlFail() if false
is returned from a function in
SWI-Prolog.h
. If the wrapper functions or class methods are
used, Prolog errors result in a C++ PlException
exception.4If
a “Plx_'' wrapper is used to call a SWI-Prolog.h
function, a Prolog error will have already resulted in throwing PlException
;
PlCheckFail(rc) is used to additionally throw
PlFail
, similar to returning false
from the
top-level of a foreign predicate - Prolog will check for an error and
call throw/1 if
appropriate.PlException
class is a subclass of std::exception
and encapsulates a Prolog error. Prolog errors are converted into throw
PlException(...)
. If the user code does not catch the PlException
,
the PREDICATE() macro converts the error to a Prolog error upon return
to the Prolog caller.(char*)t
, (int64_t)t
,
static_cast<char*>(t)
) have been deprecated, replaced
by "getters" (e.g.,
t.as_string()
, t.as_int64_t()
).std::string
, comparison operators. The as_string() method
allows specifying the encoding to use whereas the ==
and similar operators do not allow for this.char*
have been replaced by methods
that return std::string
to ensure that lifetime issues
don't cause subtle bugs.5If you
want to return a char*
from a function, you should not do return
t.as_string().c_str()
because that will return a pointer to local
or stack memory. Instead, you should change your interface to return a std::string
and apply the c_str()
method to it. These lifetime errors
can sometimes be caught by specifying the Gnu C++ or Clang
options -Wreturn-stack-address
or -Wreturn-local-addr
- as of 2023-04, Clang seems to do a better analysis.char*
or wchar_t*
arguments also accept std::string
or std::wstring
arguments. Where possible, encoding
information can also be specified.PlString
has been renamed to PlTerm_string
to make it clear that it's a term that contains a Prolog string.PL_...(term_t, ...)
methods have been added to PlTerm
,
and PL_...(atom_t, ...)
methods have been added to PlAtom
.
Where appropriate, the arguments use PlTerm
, PlAtom
,
etc. instead of term_t
, atom_t
, etc.int
for
true/false now return a C++ bool
.term_t
, atom_t
,
etc.) have been renamed from handle
, ref
, etc.
to
C_
.6This is done by
subclassing from Wrapped<term_t>
, Wrapped<atom_t>
,
etc., which define the field C_
, standard constructors, the
methods is_null(), not_null(), reset(), reset(v), reset_wrapped(v), plus
the constant null
. This value can be accessed
by the unwrap() and unwrap_as_ptr() methods. There is also a "friend"
function PlUnwrapAsPtr().PlStringBuffers
provides a simpler interface for
allocating strings on the stack than PL_STRINGS_MARK() and PL_STRINGS_RELEASE().
See section 2.5.7.1.PlStream
provides a simpler interface for streams than
PL_get_stream(), PL_acquire_stream(), and PL_release_stream().
See section 2.5.7.2.record_t
have been added. The
PlRecordExternalCopy
class contains the opaque handle, as a
convenience.control_t
has been added and the
PREDICATE_NONDET() has been modified to use it.More details are given in section 2.7 and section 2.8.