Template wizardry and its cost

Steven Schveighoffer schveiguy at gmail.com
Tue Jun 21 02:35:28 UTC 2022


On 6/20/22 7:01 PM, Bastiaan Veelo wrote:
> As you and Adam pointed out, this may not be worth the trouble; But just 
> to see if I can, I tried to extend your trick to a function taking an 
> argument. I didn't find a way without using a delegate, and that gives a 
> deprecation warning for escaping a reference. Can it be fixed? The code 
> below leaves out the string extraction version, but is otherwise 
> complete and can be pasted into [run.dlang.io](https://run.dlang.io/).

structs can be functors:

```d
private @safe struct TranslatableStringPlural
{
     string _str, _strpl;
     this(string s1, string s2) { // this is unfortunately necessary
         _str = s1;
         _strpl = s2;
     }
     string opCall(int n)
     {
         auto fmt = ngettext(_str, _strpl, n);
         if (countFormatSpecifiers(fmt) == 0)
             // Hack to prevent orphan format arguments if "%d" is 
replaced by "one" in the singular form:
             return ()@trusted{ return fromStringz(&(format(fmt~"\0%s", 
n)[0])); }();
         return format(fmt, n);
     }
}
```

I will say, I find this line... reprehensible ;)

```d
return ()@trusted{ return fromStringz(&(format(fmt~"\0%s", n)[0])); }();
```

Actually, the whole function (and the format specifier counter, etc) is 
very obtuse.

How about:

```d
private @safe struct Strplusarg {
     this(string s) {
         fmt = s;
         auto fs = countFormatSpecifiers(fmt);
         assert(fs == 0 || fs == 1, "Invalid number of specifiers"); // 
bonus sanity check
         hasArg = fs == 1;
     }
     string fmt;
     bool hasArg;
}

private @safe struct TranslatableStringPlural
{
     Strplusarg _str, _strpl;
     this(string s1, string s2) { // this is unfortunately necessary
         _str = s1;
         _strpl = s2;
     }
     string opCall(int n)
     {
         auto f = n == 1 ? _str : _strpl;
         return f.hasArg ? format(f.fmt, n) : f.fmt;
     }
}
```

And we can fix your countFormatSpecifiers function so it doesn't have 
the __ctfe branch

```d
@safe: private:
int countFormatSpecifiers(string fmt) pure
{
     static void ns(const(char)[] arr) {} // the simplest output range
     auto nullSink = &ns;
     int count = 0;
     auto f = FormatSpec!char(fmt);
     while (f.writeUpToNextSpec(nullSink))
         count++;
     return count;
}
```

But.... I don't see any actual translation happening in the 
plural/singular form? Is that expected? If it's supposed to happen in 
ngettext, that translation surely has to be done inside the opCall, and 
if you can vary the parameter count based on language, then so does the 
count for the argument specifiers.

In any case, lots to ingest and figure out how it fits your needs.

-Steve


More information about the Digitalmars-d mailing list