www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Linker Error with Template Function

reply Kyle Ingraham <kyle kyleingraham.com> writes:
I am writing a library where I would like to be able to store 
instances of a type of class to an associative array for later 
usage. Each class stored has to implement a function as part of 
the required interface. The argument given is always the same 
type but the return value should be flexible. I solved this with 
an interface:

```d
interface PathConverter
{
     T toD(T)(const string value)  safe;
}
```

That interface lets me type the associative array and any other 
part of the library that needs to use implementers of that 
interface e.g.

```d
PathConverter[string] converters;
```

The problem I'm running into is that when compile the library I 
receive the following error during linking:

```
error LNK2019: unresolved external symbol 
_D3app13PathConverter__T3toDTAyaZQjMFNfxAyaZQp referenced in 
function 
_D3app14TypedURLRouter__T10setHandlerTPFNfC4vibe4http6server17HTTPServerRequestCQBlQBjQBh18HTTPServerResponseAyaZvZQDmMFEQDaQCy6common10HTTPMethodQBlQEhZ__T9__lambda4TQEvTQDoTASQGt16PathCaptureGroupZQBrMFNfQGiQFaQBlZv

fatal error LNK1120: 1 unresolved externals

Error: linker exited with status 1120
```

The call is within a delegate to a function that returns a class 
instance from the associative array. At runtime I fill the 
associative array. The call looks like this:

```d
tailArgs[i] = getPathConverter("id 
string").toD!(Parameters!(handler)[i])("string to convert");
```

Am I running into this error because the linker can't find the 
instantiation of the template method? How would I give the linker 
the information it needs? Is there a better way to have an 
interface with flexible return values?
Sep 12 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 13 September 2022 at 00:57:58 UTC, Kyle Ingraham 
wrote:
 I am writing a library where I would like to be able to store 
 instances of a type of class to an associative array for later 
 usage. Each class stored has to implement a function as part of 
 the required interface. The argument given is always the same 
 type but the return value should be flexible. I solved this 
 with an interface:

 ```d
 interface PathConverter
 {
     T toD(T)(const string value)  safe;
 }
 ```
https://dlang.org/spec/template.html#limitations
 Templates cannot be used to add non-static fields or virtual 
 functions to classes or interfaces.
You *should* get an error from the compiler for trying to do this, instead of just a linker error somewhere else down the line, but either way it's not going to work. You'll have to find another solution.
Sep 12 2022
parent reply Kyle Ingraham <kyle kyleingraham.com> writes:
On Tuesday, 13 September 2022 at 01:46:14 UTC, Paul Backus wrote:
 On Tuesday, 13 September 2022 at 00:57:58 UTC, Kyle Ingraham 
 wrote:
 I am writing a library where I would like to be able to store 
 instances of a type of class to an associative array for later 
 usage. Each class stored has to implement a function as part 
 of the required interface. The argument given is always the 
 same type but the return value should be flexible. I solved 
 this with an interface:

 ```d
 interface PathConverter
 {
     T toD(T)(const string value)  safe;
 }
 ```
https://dlang.org/spec/template.html#limitations
 Templates cannot be used to add non-static fields or virtual 
 functions to classes or interfaces.
You *should* get an error from the compiler for trying to do this, instead of just a linker error somewhere else down the line, but either way it's not going to work. You'll have to find another solution.
Thanks for the spec help Paul. I must've skirted around the compiler somehow. This is a minimal example that triggers the linker error: ```d interface PathConverter { T toD(T)(string value); } class NumberConverter(T) : PathConverter { T toD(T)(string value) { import std.conv : to; return to!T(value); } } alias IntConverter = NumberConverter!int; void main() { PathConverter[string] allConverters; allConverters["int"] = new IntConverter; int converted = allConverters["int"].toD!int("9"); } ``` Any suggestions for being able to call one function for any instance given but maintain flexible return types?
Sep 12 2022
parent reply Nick Treleaven <nick geany.org> writes:
On Tuesday, 13 September 2022 at 03:00:17 UTC, Kyle Ingraham 
wrote:
 Any suggestions for being able to call one function for any 
 instance given but maintain flexible return types?
Not sure if it helps, but you can define final methods in an interface, which can call virtual interface methods: ```d interface PathConverter { string getValue(); final T toD(T)() { import std.conv : to; return to!T(getValue()); } } ``` Not tested as AFK.
Sep 13 2022
parent reply Kyle Ingraham <kyle kyleingraham.com> writes:
On Tuesday, 13 September 2022 at 08:43:45 UTC, Nick Treleaven 
wrote:
 On Tuesday, 13 September 2022 at 03:00:17 UTC, Kyle Ingraham 
 wrote:
 Any suggestions for being able to call one function for any 
 instance given but maintain flexible return types?
Not sure if it helps, but you can define final methods in an interface, which can call virtual interface methods: ```d interface PathConverter { string getValue(); final T toD(T)() { import std.conv : to; return to!T(getValue()); } } ``` Not tested as AFK.
Thanks for the suggestion Nick. I solved this by storing structs as `void*` in a wrapper struct with information about their module and identifier saved elsewhere. I use that information to setup casts to the appropriate type then call `toD`. That way I can call the same method for functions that return different types and store disparate structs to the same wrapper struct. The wrapper struct gets used in function signatures.
Oct 01 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/1/22 11:15, Kyle Ingraham wrote:

 storing structs as
 `void*` in a wrapper struct with information about their module and
 identifier saved elsewhere.
Perhaps unrelated but that part reminded me of the following discussion: https://forum.dlang.org/post/tfbn10$19nv$1 digitalmars.com Ali
Oct 01 2022
parent Kyle Ingraham <kyle kyleingraham.com> writes:
On Saturday, 1 October 2022 at 21:18:05 UTC, Ali Çehreli wrote:
 On 10/1/22 11:15, Kyle Ingraham wrote:

 storing structs as
 `void*` in a wrapper struct with information about their
module and
 identifier saved elsewhere.
Perhaps unrelated but that part reminded me of the following discussion: https://forum.dlang.org/post/tfbn10$19nv$1 digitalmars.com Ali
Thanks for this Ali. I found it useful to see another way to solve this problem. Seems like it would be great to have a `Type` type that can store a type at compile-time for use at run-time.
Oct 15 2022