【问题标题】:Mapping variadic template arguments in D在 D 中映射可变参数模板参数
【发布时间】:2012-10-15 01:40:07
【问题描述】:

是否有任何内置或库提供的方法来映射 D 中的一组可变参数模板参数?

例如:

void foo(Args...)(Args args)
{
    bar(fun(args));
}

我希望它扩展到:

void foo(Args...)(Args args)
{
    bar(fun(args[0]), fun(args[1]), fun(args[2]), /* ... */);
}

C++11 可变参数模板支持这一点。你如何在 D 中做同样的事情?

【问题讨论】:

    标签: templates metaprogramming d variadic-templates


    【解决方案1】:

    这是一个使用最新版本的 D 编译器编译的更新版本:

    /**
        Return a Tuple expression of $(D Func) being
        applied to every tuple argument.
    */
    template Map(alias Func, args...)
    {
        static auto ref ArgCall(alias Func, alias arg)() { return Func(arg); }
    
        static if (args.length > 1)
            alias Map = TypeTuple!(ArgCall!(Func, args[0]), Map!(Func, args[1 .. $]));
        else
            alias Map = ArgCall!(Func, args[0]);
    }
    
    ///
    unittest
    {
        import std.conv;
    
        int square(int arg)
        {
            return arg * arg;
        }
    
        int refSquare(ref int arg)
        {
            arg *= arg;
            return arg;
        }
    
        ref int refRetSquare(ref int arg)
        {
            arg *= arg;
            return arg;
        }
    
        void test(int a, int b)
        {
            assert(a == 4, a.text);
            assert(b == 16, b.text);
        }
    
        void testRef(ref int a, ref int b)
        {
            assert(a++ == 16, a.text);
            assert(b++ == 256, b.text);
        }
    
        int a = 2;
        int b = 4;
    
        test(Map!(square, a, b));
    
        test(Map!(refSquare, a, b));
        assert(a == 4);
        assert(b == 16);
    
        testRef(Map!(refRetSquare, a, b));
        assert(a == 17);
        assert(b == 257);
    }
    

    【讨论】:

      【解决方案2】:

      这是我想出的最好的:

      auto staticMappedCall(alias call, alias F, T...)(T t)
      {
          T a;
          foreach(i, arg; t)
                  a[i] = F(arg);
          return call(a);
      }
      

      你可以这样使用它:

          staticMappedCall!(bar,t)(1, 2);
      

      其中 bar 是要调用的函数,t 是转换。

      void bar(int a, int b) { writeln(a, " ", b); }
      int t(int a) { return a*2; }
      
      staticMappedCall!(bar, t)(1, 2);
      
      > test
      2 4
      

      【讨论】:

      • 实际上,如果转换函数返回不同的类型,这不一定有效。但是如果你确实 import std.traits; ParameterTypeTuple!call a;而不是 T a;,我认为可以做到这一点。
      • 还有一个问题:当 T 包含不可变类型时它不起作用。我认为做到这一点的唯一方法是使用字符串混合。我现在正在处理 Phobos 的拉取请求。
      • 我的实现适用于具有不可变字段的类型:stackoverflow.com/a/12926873/279684
      猜你喜欢
      • 2023-03-24
      • 2016-12-01
      • 2021-11-26
      • 1970-01-01
      • 2013-10-09
      • 2013-09-14
      • 1970-01-01
      • 2013-09-22
      • 2016-10-06
      相关资源
      最近更新 更多