Template wizardry and its cost

Bastiaan Veelo Bastiaan at Veelo.net
Mon Jun 20 23:01:16 UTC 2022


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/).

-- Bastiaan.

```d
--- app.d
import gettext;
import std.stdio;

void main()
{
     foreach (n; 0 .. 3)
         writeln(tr!("one goose.", "%d geese.")(n));
}

--- gettext.d
import std;

private @safe struct TranslatableString
{
     string _str;
     string get()
     {
         return gettext(_str);
     }
     alias get this;
}
private @safe struct TranslatableStringPlural
{
     string _str, _strpl;
     string callFormat(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);
     }
     string delegate(int) get()
     {
         return &callFormat;
     }
     alias get this;
}
template tr(string singular, string plural = null)
{
     static if (plural == null)
         enum tr = TranslatableString(singular);
     else
         enum tr = TranslatableStringPlural(singular, plural);
}

@safe: private:
int countFormatSpecifiers(string fmt) pure
{
     int count = 0;
     auto f = FormatSpec!char(fmt);
     if (!__ctfe)
     {
         while (f.writeUpToNextSpec(nullSink))
             count++;
     } else {
         auto a = appender!string; // std.range.nullSink does not 
work at CT.
         while (f.writeUpToNextSpec(a))
             count++;
     }
     return count;
}
// Translation happens here:
string gettext(string str)
{
     return str;
}
string ngettext(string singular, string plural, int n)
{
     return n == 1 ? singular : plural;
}
```


More information about the Digitalmars-d mailing list