You should be able to instantiate the function using a Pointer. That is, you can write
func PointerOrError[T any](s C.StatusOr) (t T, err error) { var ptr unsafe.Pointer ptr, err = UnsafePointerOrError(s) // <-- unsafe.Pointer, error if err != nil { return } return *(*T)(unsafe.Pointer(&ptr)) } func main() { var s C.StatusOr p := PointerOrError[*C.mystruct](s) _ = p } It's unfortunate, of course, that this would allow you to instantiate the function using a non-pointer as well, but it seems that's impossible to prevent statically? You can catch it dynamically by doing something akin to if k := reflect.TypeOf(*new(T)).Kind(); k != reflect.Pointer && k != reflect.UnsafePointer { panic("PointerOrError must be instantiated with pointer type") } Obviously, none of this is ideal, but maybe it's the best you can do - apart from generating code. On Sat, Apr 15, 2023 at 8:48 PM Jan <pfei...@gmail.com> wrote: > Re-factoring your example to use CGO, in a small main.go file: > > ``` > $ go run . > ./main.go:28:10: cannot use incomplete (or unallocatable) type as a type > argument: main._Ctype_struct_MyThing > $ cat main.go > package main > > // struct MyThing; > // typedef struct MyThing MyThing; > import "C" > import ( > "fmt" > "unsafe" > ) > import "flag" > > func PointerOrError[T *Q, Q any](s int) (t T, err error) { > var ptr unsafe.Pointer > ptr, err = UnsafePointerOrError(s) // <-- unsafe.Pointer, error > if err != nil { > return > } > t = (T)(ptr) > return > } > > func UnsafePointerOrError(v int) (unsafe.Pointer, error) { > return unsafe.Pointer(&v), nil > } > > func main() { > flag.Parse() > t, _ := PointerOrError[*C.MyThing](1) > fmt.Println(t) > } > ``` > > > On Saturday, April 15, 2023 at 8:41:28 PM UTC+2 Jan wrote: > >> Thanks! I hadn't realized that one could constraint T to be a pointer >> type by using a second type paramater Q, this in nice. >> >> But alas, it doesn't work. When I copy&pasted your code to mine, and used >> an undefined C type ... it complained of the same thing: >> >> ``` >> cannot use incomplete (or unallocatable) type as a type argument: >> gomlx/xla._Ctype_struct_StableHLOHolder >> ``` >> >> I'm using it in the following snipped of code: >> >> ``` >> func (comp *Computation) ToStableHLO() (*StableHLO, error) { >> if comp.IsNil() || comp.firstError != nil { >> return nil, errors.Errorf("Computation graph is nil!?") >> } >> statusOr := C.ConvertComputationToStableHLO(comp.cCompPtr) >> cPtr, err := PointerOrError[*C.StableHLOHolder](statusOr) >> if err != nil { >> return nil, errors.Wrapf(err, "failed conversion in >> Computation.ToStableHLO") >> } >> return NewStableHLO(cPtr), nil >> } >> ``` >> >> I suspect it doesn't allow matching Q to an incomplete type >> (`C.StableHLOHolder` in this example), same way as my original version :( >> >> I think your example in playground doesn't capture that -- the playground >> doesn't seem to allow CGO code (i tried this >> <https://go.dev/play/p/ZM14sQuK8iN?v=gotip.go?download=true>, but it >> didn't even try to compile). >> >> I mean it's not the end of the world, I can always cast it in the next >> line ... it's just one of those little things that would be "ergonomically" >> very nice if it worked :) >> >> >> >> On Saturday, April 15, 2023 at 3:02:14 PM UTC+2 jake...@gmail.com wrote: >> >>> What About: >>> >>> func PointerOrError[T *Q, Q any](s C.StatusOr ) (t T, err error) >>> >>> Seems to compile: https://go.dev/play/p/n4I-XkONj-O?v=gotip >>> >>> On Saturday, April 15, 2023 at 6:28:39 AM UTC-4 Jan wrote: >>> >>>> hi, >>>> >>>> This is a variation for a previous topic >>>> <https://groups.google.com/g/golang-nuts/c/h75BwBsz4YA/m/FLBIjgFBBQAJ>, >>>> but since there isn't a clear solution, I thought I would ask if anyone can >>>> think of a work around. >>>> >>>> I've been interacting a lot with C++ libraries from Go, and one of the >>>> commonly returned types is an abls::StatusOr >>>> <https://abseil.io/docs/cpp/guides/status>, for which I created a >>>> simple C wrapper that casts the error and value to a `char *` and `void *` >>>> respectively (dropping the type information in between C++ and Go). >>>> >>>> In Go I want to return the type information, so I defined a small >>>> generic function: >>>> >>>> // PointerOrError converts a StatusOr structure to either a pointer to >>>> T with the data >>>> // or the Status converted to an error message and then freed. >>>> func PointerOrError[T any](s C.StatusOr) (*T, error) { >>>> ptr, err := UnsafePointerOrError(s) // returns unsafe.Pointer, error >>>> if err != nil { >>>> return nil, err >>>> } >>>> return (*T)(ptr), nil >>>> } >>>> >>>> Now this doesn't work for my forward declared C++ types (most of them >>>> are just aliases to C++ objects) -- Go complaints with: `cannot use >>>> incomplete (or unallocatable) type as a type argument`, because `T` is >>>> incomplete indeed. >>>> >>>> But ... I will never instantiate `T`, I only care about `*T`, which is >>>> not incomplete. >>>> >>>> But there isn't a way to say a generics attribute is a pointer. So if I >>>> use the following: >>>> >>>> func PointerOrError2[T any](s C.StatusOr) (t T, err error) { >>>> var ptr unsafe.Pointer >>>> ptr, err = UnsafePointerOrError(s) // <-- unsafe.Pointer, error >>>> if err != nil { >>>> return >>>> } >>>> t = (T)(ptr) >>>> return >>>> } >>>> >>>> And instantiate it with a `PointerOrError2[*MyType](statusOr)` for >>>> instance, I get, as expected: >>>> >>>> cannot convert ptr (variable of type unsafe.Pointer) to type T >>>> >>>> Any suggestions to make this work ? >>>> >>>> I could probably craft something using the `reflect` package, but I was >>>> hoping for a smart (and likely faster?) generics solution. >>>> >>>> cheers >>>> Jan >>>> >>>> >>>> >>>> >>>> >>>> >>>> -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/639d57d5-37da-424b-a137-41a7bca7e821n%40googlegroups.com > <https://groups.google.com/d/msgid/golang-nuts/639d57d5-37da-424b-a137-41a7bca7e821n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGmp5utKkj6kH87RyYa5M8mQA15jKf6G86vku2_JqXO3w%40mail.gmail.com.