Open haxscramper opened 3 years ago
can you simplify to the maximum and show a reduced case with no reference to C++ stdlib?
this will make analysis easier to find a good solution
const h = "wrap_inner.hpp"
type
P[T] {.importcpp: "P<'0>", header: h.} = object
f: T
S[T] {.importcpp: "S<'0>", header: h.} = object
# Have to declare additional object, cannot port procedures/fields of
# `P`. When compiled to C++ this type /is/ actually a `P[T]`
S_value_type[T] {.importcpp: "S<'0>::value_type", header: h.} = object
f: T # In order for `echo` to work correctly I need to port all fields.
proc get[T](s: S[T], arg: T): S_value_type[T] {.importcpp: "#.get(@)", header: h.}
proc initS[T](): S[T] {.importcpp: "S<'*0>()", header: h.}
proc main() =
let s = initS[cint]().get(1)
echo s
main()
template <typename T>
struct P {
T f;
};
template <typename T>
struct S {
typedef P<T> value_type;
value_type get(T arg) {
return P<T>{arg};
};
};
C++ allows for nested
structures
,classes
,unions
andtypedef
declarations, which are often used in template metaprogramming. For example, consider definitions of thestd::basic_string
(std::string
is atypedef
of this class). It has several inner declarations for various types, such as::const_pointer
,::const_iterator
and more. I will not go over all of them, and instead will focus on one, that recently triggered another edge case in the implementation.An object of this type is returned by
cbegin()
method, and some other elements.basic_string
implementation does not rely too much on this iterator, and it is mainly interesting because of how it is implemented. If we go tobits/stl_iterator.h
, and find__normal_iterator
implementation, we could see this (unimportant parts are omitted, full implementation can be found at stdc++ mirror):Question - what is the type of
*std::basic_string<char>.cbegin()
? We get__normal_iterator
fromcbegin()
and then dereference it viaoperator*
... whose return type isreference
. Which has nothing to do with any of the template type parameters for any of the involved types, at least not directly. The return type of theoperator*
is defined in terms of innertypedef
for a template parameter. Specifically::reference
, which is a__traits_type::reference
, where_traits_type = std::iterator_traits<_Iterator>
, where_Iterator
is a template type parameter.I've come with a couple ways of solving this problem, none of which are satisfactory.
cbegin()
withCxxIterator[char]
, which has[]
implementation. Could work, does not scale well since I would have to manually (or semi-automatically) correct a lot of code.typedef
s as well (right now they are ignored), and implement[]
overload. This is problematic, since innertypedef
, as we have already seen, does not provide enough information to reconstruct the same behavior in nim code.typedef
inside of nim type declaration, which means it must a separateobject
, to allow forstd::basic_string<'0, '1, '2>::const_pointer
(because no way in hell I I will be able to decipher the wholetypedef
chain - (1)const_pointer
is a_Alloc_traits::const_pointer
where (2)_Alloc_traits
is a__gnu_cxx::__alloc_traits<_Char_alloc_type>
where (3)_Char_alloc_type
is a__gnu_cxx::__alloc_traits<_Alloc>::template rebind<_CharT>::other
where (4)_CharT
and_Alloc
are actual template type parameters. Wrapping this would mean jumping into internal implementation details that are clearly not needed*)byref
,CxxBase
etc. is needed in order to be able to reuse base iterator methods. Otherwise, I have to copy object methods for each instantiation, which is even worse than #1, where it was capped at number of derived classes, while this would be repeated for each innertypedef
.For the reference,
basic_string
has 14 - (traits_type
,value_type
,allocator_type
,size_type
,difference_type
,reference
,const_reference
,pointer
,const_pointer
,iterator
, basic_string,
const_reverse_iterator,
reverse_iterator,
const_iterator`)Then, I need to implement an absolute abomination of a procedure, that does two unpacking of the template parameters in order to get to the
char
one:Maybe there are more solutions that I'm not aware of, but this is a showstopper for wrapping things like C++ stdlib.