digitalmars.D.learn - Is there a way to get a =?UTF-8?B?dGVtcGxhdGXigJlz?= parameters and
- Quirin Schroll (14/14) Jan 20 2023 Is there a trait (or a combination of traits) that gives me the
- Steven Schveighoffer (4/21) Jan 20 2023 No, there is no way to introspect anything about a template's details
- Adam D Ruppe (2/4) Jan 20 2023 No, reflection over templates is very limited.
- Salih Dincer (4/6) Jan 20 2023 If I'm not mistaken, the following will help:
- Adam Ross Walker (260/260) Jan 22 2023 There is a way but it's horrible. You can take the `.stringof`
- Adam Ross Walker (3/5) Jan 22 2023 Apologies, I missed the key part of your question. But I think
Is there a trait (or a combination of traits) that gives me the constraints of a template? Example: ```D void f(T1 : long, T2 : const(char)[])(T x) { } template constraintsOf(alias templ) { /*Magic here*/ } alias constraints = constraintsOf!f; // tuple(long, const(char)[]) ``` At the moment, I care about constraints that are types. I don’t care about value or alias constraints (e.g. `opBinary(string op : "+")(..)` or `f(alias x : something)()`, but if it works for types, it should probably work for other constraints as well. For what I want, `constraintsOf` may expect every template parameter to be a type and to have a constraint.
Jan 20 2023
On 1/20/23 12:15 PM, Quirin Schroll wrote:Is there a trait (or a combination of traits) that gives me the constraints of a template? Example: ```D void f(T1 : long, T2 : const(char)[])(T x) { } template constraintsOf(alias templ) { /*Magic here*/ } alias constraints = constraintsOf!f; // tuple(long, const(char)[]) ``` At the moment, I care about constraints that are types. I don’t care about value or alias constraints (e.g. `opBinary(string op : "+")(..)` or `f(alias x : something)()`, but if it works for types, it should probably work for other constraints as well. For what I want, `constraintsOf` may expect every template parameter to be a type and to have a constraint.No, there is no way to introspect anything about a template's details until its instantiated. -Steve
Jan 20 2023
On Friday, 20 January 2023 at 17:15:31 UTC, Quirin Schroll wrote:Is there a trait (or a combination of traits) that gives me the constraints of a template?No, reflection over templates is very limited.
Jan 20 2023
On Friday, 20 January 2023 at 17:15:31 UTC, Quirin Schroll wrote:For what I want, `constraintsOf` may expect every template parameter to be a type and to have a constraint.If I'm not mistaken, the following will help: https://dlang.org/phobos/std_range_primitives.html SDB 79=
Jan 20 2023
There is a way but it's horrible. You can take the `.stringof` and parse the result. I knocked this up for something but it's not well tested and there are probably templates that it handles incorrectly. I'm not claiming this is any good, I just happened to have it. ```d enum TemplateParameterType { valueType, aliasType, typeType, thisType, sequenceType } public struct TemplateParameter { TemplateParameterType type; string name; string defaultValue; } public auto templateParameters(alias T)() { static assert(__traits(isTemplate, T)); import std.algorithm : startsWith; import std.array : appender; import std.string : strip; auto results = appender!(TemplateParameter[]); auto isMissing = false; const templateSignature = T.stringof; const allParametersStart = findExpectedSource(templateSignature, '(', isMissing) + 1; const allParametersEnd = allParametersStart + findExpectedSource(templateSignature[allParametersStart .. $], ')', isMissing); if (isMissing) throw new Exception("{Expected `(` and `)` in template signature: `" ~ templateSignature ~ "`."); auto parametersText = templateSignature[allParametersStart .. allParametersEnd]; auto parameterIndex = -1; mainParameterLoop: while (parametersText.length > 0) { parameterIndex++; auto parameterEnd = findExpectedSource(parametersText, ',', isMissing); if (isMissing) parameterEnd = parametersText.length; auto parameterRemainingText = parametersText[0 .. parameterEnd]; if (parameterEnd < parametersText.length) parametersText = parametersText[parameterEnd + 1 .. $]; else parametersText = ""; auto token = parameterRemainingText.consumeToken; if (parameterRemainingText.startsWith("...")) { results.put(TemplateParameter(TemplateParameterType.sequenceType, token, "")); continue mainParameterLoop; } auto nextToken = parameterRemainingText.consumeToken; if (nextToken == "") { results.put(TemplateParameter(TemplateParameterType.typeType, token, "")); continue mainParameterLoop; } TemplateParameterType type; if (token == "this") type = TemplateParameterType.thisType; else if (token == "alias") type = TemplateParameterType.aliasType; else if (nextToken == ":" || nextToken == "=") type = TemplateParameterType.typeType; else type = TemplateParameterType.valueType; if (type != TemplateParameterType.typeType) { token = nextToken; nextToken = parameterRemainingText.consumeToken; } while (true) { if (nextToken == "") { results.put(TemplateParameter(type, token, "")); continue mainParameterLoop; } if (nextToken == ":") { const identifierName = token; while (true) { token = parameterRemainingText.consumeToken; if (token.length == 0) { results.put(TemplateParameter(type, identifierName, "")); continue mainParameterLoop; } else if (token == "=") { results.put(TemplateParameter(type, identifierName, parameterRemainingText.strip)); continue mainParameterLoop; } } results.put(TemplateParameter(type, identifierName, parameterRemainingText.strip)); continue mainParameterLoop; } if (nextToken == "=") { const identifierName = token; results.put(TemplateParameter(type, identifierName, parameterRemainingText.strip)); continue mainParameterLoop; } token = nextToken; import std.conv : to; if (token.length == 0) throw new Exception("Cannot parse parameter " ~ parameterIndex.to!string ~ " in template `" ~ templateSignature ~ "`."); nextToken = parameterRemainingText.consumeToken; } } return results[]; } private auto findExpectedCharacter(string source, char character, out bool isMissing) { foreach (offset; 0 .. source.length) if (source[offset] == character) return offset; isMissing = true; return 0; } private auto findExpectedText(string source, string text, out bool isMissing) { import std.algorithm : startsWith; foreach (offset; 0 .. source.length) if (source[offset .. $].startsWith(text)) return offset; isMissing = true; return 0; } private auto findExpectedSource(string source, char character, out bool isMissing) { auto offset = 0L; while (true) { if (offset >= source.length) isMissing = true; else if (source[offset] == character) return offset; else if (source[offset] == '(') offset += findExpectedSource(source[offset + 1 .. $], ')', isMissing) + 1; else if (source[offset] == '[') offset += findExpectedSource(source[offset + 1 .. $], ']', isMissing) + 1; else if (source[offset] == '{') offset += findExpectedSource(source[offset + 1 .. $], '}', isMissing) + 1; else if (source[offset] == '"') offset += findExpectedCharacter(source[offset + 1 .. $], '"', isMissing) + 1; else if (source[offset] == '\'') offset += findExpectedCharacter(source[offset + 1 .. $], '\'', isMissing) + 1; else if (source[offset] == '/' && offset + 1 < source.length && source[offset + 1] == '/') offset += findExpectedCharacter(source[offset + 1 .. $], '\n', isMissing) + 1; else if (source[offset] == '/' && offset + 1 < source.length && source[offset + 1] == '*') offset += findExpectedText(source[offset + 1 .. $], "*/", isMissing) + 1; if (isMissing) return 0; offset++; } } private string consumeToken(ref string text) { import std.uni : isWhite, isAlphaNum; // Chew up any preceding white space. while (text.length > 0 && text[0].isWhite) text = text[1 .. $]; auto offset = 0; while (offset < text.length && (text[offset].isAlphaNum || text[offset] == '_')) offset++; if (offset == 0 && text.length > 0) offset++; const result = text[0 .. offset]; if (offset < text.length) text = text[offset .. $]; else text = ""; return result; } unittest { void testTemplate(alias t, size_t line = __LINE__)(TemplateParameter[] expected) { import std.conv : to; const parameters = templateParameters!t; assert(parameters == expected, "\n\nTest failure on line " ~ line.to!string ~ ": \n" ~ "Parameters: " ~ parameters.to!string ~ "\n" ~ "Expected: " ~ expected.to!string ~ "\n"); } template t1() { } testTemplate!t1([]); template t2(int p) { } testTemplate!t2([TemplateParameter(TemplateParameterType.valueType, "p", "")]); template t3(int p = 1) { } testTemplate!t3([TemplateParameter(TemplateParameterType.valueType, "p", "1")]); template t4(int p1, string p2) { } testTemplate!t4([TemplateParameter(TemplateParameterType.valueType, "p1", ""), TemplateParameter(TemplateParameterType.valueType, "p2", "")]); template t5(int p1 = 123, string p2 = "ABC") { } testTemplate!t5([TemplateParameter(TemplateParameterType.valueType, "p1", "123"), TemplateParameter(TemplateParameterType.valueType, "p2", "\"ABC\"")]); template t6(alias p) { } testTemplate!t6([TemplateParameter(TemplateParameterType.aliasType, "p", "")]); template t7(alias p = 12.34) { } testTemplate!t7([TemplateParameter(TemplateParameterType.aliasType, "p", "12.34")]); class ThisTemplateTest { template t8(this p) { } } const thisTemplateTest = new ThisTemplateTest; testTemplate!(thisTemplateTest.t8)([TemplateParameter(TemplatePar meterType.thisType, "p", "")]); template t9(p...) { } testTemplate!t9([TemplateParameter(TemplateParameterType.sequenceType, "p", "")]); template t10(T) { } testTemplate!t10([TemplateParameter(TemplateParameterType.typeType, "T", "")]); template t11(alias a_b_c = "a_b_c") { } testTemplate!t11([TemplateParameter(TemplateParameterType.aliasType, "a_b_c", "\"a_b_c\"")]); class C { } template t12(T : C) { } testTemplate!t12([TemplateParameter(TemplateParameterType.typeType, "T", "")]); } ```
Jan 22 2023
On Friday, 20 January 2023 at 17:15:31 UTC, Quirin Schroll wrote:Is there a trait (or a combination of traits) that gives me the constraints of a template?Apologies, I missed the key part of your question. But I think the above can be adapted if you were so inclined.
Jan 22 2023