【问题标题】:How to inspect the types of a function's parameters?如何检查函数参数的类型?
【发布时间】:2012-02-08 06:36:20
【问题描述】:

我有一个应用程序,我正在构建一个函数marshal_and_apply,它使用一些参数调用其他函数(或仿函数)fmarshal_and_apply 的工作是根据 f 的参数类型对参数应用一些特殊的编组。

如果f 的参数之一属于特殊类型marshal_me<T>,则marshal_and_apply 将在将参数传递给f 之前通过一些专门分配的存储空间来编组该参数。为了执行分配,marshal_and_apply 必须知道所有参数的存储要求,然后才能封送任何参数。


一些例子:

template<typename Function, typename... Args>
void marshal_and_apply(Function f, Args... args);

void func1(int x, int y);
void func2(marshal_me<int> x, int y);
void func3(marshal_me<int> x, marshal_me<int> y, marshal_me<int> z);

// this call would be equivalent to:
// func1(7,13)
marshal_and_apply(func1, 7, 13);

// this call would be equivalent to:
// auto storage = my_allocator(sizeof(int));
// auto x = marshal_me<int>(7, storage);
// func2(x, 13);
marshal_and_apply(func2, 7, 13);

// this call would be equivalent to:
// auto storage = my_allocator(sizeof(int) + sizeof(int) + sizeof(int));
// auto x = marshal_me<int>(7, storage);
// auto y = marshal_me<int>(13, storage + sizeof(int));
// auto z = marshal_me<int>(42, storage + sizeof(int) + sizeof(int));
// func3(x,y,z);
marshal_and_apply(func3, 7, 13, 42);

为了解决这个问题,marshal_and_apply 似乎需要一种机制来检查f 的参数类型。我怀疑这通常是不可能的,但可以识别一组特殊类型(在本例中为marshal_me&lt;T&gt;)中的一个是否可以转换为特定参数的类型。

我应该如何构建marshal_and_apply

【问题讨论】:

  • 在你的第二个例子中,我看不到你用7 做了什么。你的意思是auto x = marshal_me&lt;int&gt;(storage, 7); 还是什么?
  • @AaronMcDaid 是的,我已经更正了。
  • 如果marshal_me&lt;int&gt; 有一个构造函数采用int,你无论如何都可以调用func2(7, 13)。包装器有什么额外的好处?
  • @BenJackson 这个例子是人为的。完整的解释超出了本文的范围,但由于 GPU 编程的特殊要求,我需要以特定方式为函数参数分配内存。

标签: c++ templates c++11 parameter-passing


【解决方案1】:

可能是这样的:

template<typename Function, typename... Args>
void marshal_and_apply(Function f, Args &&... args)
{
    f(InspectAndModify<Args>::process(sizeof...(Args), std::forward<Args>(args))...);
}

现在定义:

template <typename T> struct InspectAndModify
{
    static T&& process(unsigned int N, T && t)
    {
        return std::forward<T>(t);
    }
};

template <typename T> struct InspectAndModify<marshal_me<T>>
{
     static T&& process(unsigned int N, marshal_me<T> && m)
     {
         /* ... */
     }
};

完全不同的东西:这种方法首先剖析函数签名,然后对每对类型执行“静态转换”,您可以在其中插入 marshal_me 特化:

template <typename T> struct marshal_me { marshal_me(T) { } };

template <typename To, typename From> struct static_transform;

template <typename T> struct static_transform<T, T>
{
  static T go(T t) { return t; }
};

template <typename T> struct static_transform<T, T&>
{
  static T go(T & t) { return t; }
};

template <typename T> struct static_transform<marshal_me<T>, T>
{
  static marshal_me<T> go(T && t) { return std::forward<T>(t); }
};

template<typename T, typename... Args>
struct marshal_impl
{
  template <typename ...Urgs>
  static T go(T(*f)(Urgs...), Args &&... args)
  {
    return f(static_transform<Urgs, Args>::go(std::forward<Args>(args))...);
  }
};

template<typename Function, typename... Args>
void marshal_and_apply(Function f, Args &&... args)
{
  marshal_impl<void, Args...>::go(static_cast<typename std::decay<Function>::type>(f),
                                  std::forward<Args>(args)...);
}

【讨论】:

  • 谢谢!这会有点工作,但我担心它不会解决第三个例子。 InspectAndModify::process 需要知道它需要处理的参数总数才能处理其中的任何一个。
  • @JaredHoberock:你能把sizeof...(Args)作为附加参数传递吗?
  • 到哪个函数? marshal_and_apply 的签名是固定的,但它可以将额外的信息传递给 InspectAndModify::process
  • 已更新 - 我现在将总大小传递给 process
  • 知道了;我应该更具体。问题是marshal_and_apply 没有接收marshal_me 对象作为参数——例如,它只接收ints。因此,在您的代码中,process 永远不会收到marshal_me,并且永远不会实例化该专业化。
猜你喜欢
  • 2020-05-13
  • 2011-11-24
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-11
  • 2020-03-29
  • 1970-01-01
相关资源
最近更新 更多