4

我目前正在编写一个库,我希望能够允许用户定义一个函数(声明为restrict( amp ))并允许他们将此函数传递给我的一个库函数以在concurrency::parallel_for_each循环中使用。例如:

template <typename T, typename Func>
void Foo( const concurrency::array_view<const T>& avParam, Func f ) 
{
     concurrency::array<T, 1> arrResult( avParam.extent );
     concurrency::parallel_for_each( avParam.extent, [=, &arrResult]( concurrency::index<1> index ) restrict(amp) {
          arrResult[index] = f( avParam[index] );
     } );

     // Do stuff...
}

我希望这能够工作,只要f将其声明为有效的 AMP 兼容函数,就好像我f直接用内核中的函数本身替换函数指针一样;一切都按预期工作。但是,使用f会导致以下错误:

不支持函数指针、函数引用或指向成员函数的指针。

有什么方法可以在不阻止我的用户使用 lambdas 以外的函子的情况下获得我想要的行为?

4

3 回答 3

2

引用和指针(指向兼容类型)可以在本地使用,但不能被 lambda 捕获。不允许使用函数指针、指针到指针等;既不是静态变量也不是全局变量。

如果您希望使用它们的实例,类必须满足更多规则。它们必须没有虚函数或虚继承。允许使用构造函数、析构函数和其他非虚拟函数。成员变量必须都是兼容的类型,当然可以包括其他类的实例,只要这些类符合相同的规则。您的 amp 兼容函数中的实际代码未在 CPU 上运行,因此无法执行您可能习惯执行的某些操作:

  • 递归
  • 指针铸造
  • 使用虚函数
  • 新建或删除
  • RTTI 或动态转换

您应该根据函子的 lambdas 来编写您的库,因为这些函数可以通过 restrict(amp) 内核访问。您可以执行以下操作:

template <typename T, typename Func>
void Foo(const concurrency::array_view<const T>& avParam, Func f)
{
    concurrency::array<T, 1> arrResult(avParam.extent);
    concurrency::parallel_for_each(avParam.extent, [=, &arrResult](concurrency::index<1> index) restrict(amp) 
    {
        arrResult[index] = f(avParam[index]);
    });

    // Do stuff...
}

template <typename T>
class Bar
{
public:
    T operator()(const T& v) const restrict(amp)
    {
        return v + 2;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> result(100, 0);
    array_view<const int, 1> result_av(result.size(), result);

    Foo(result_av, Bar<int>());

    return 0;
}

考虑这一点的一种方法是仿函数或 lambda 等效项创建一个容器,编译器可以确保该容器没有依赖关系,并且 C++ AMP 运行时可以在 GPU 上实例化。使用函数指针来实现这一点要困难得多。

于 2014-07-24T19:14:06.680 回答
0

我这里没有 Windows 框,所以无法重现或测试它。

不支持函数指针、函数引用或指向成员函数的指针。

这意味着

  • 函数指针 'pf' like in'R (*pf) (T)必须至少由 a 包裹std::function<R(T)> func(pf)

  • 应该func像 in 一样std::forward<std::function<R(T)>>(in_func)将调用堆栈向下传递给函数作为 [in]转发in_func

  • 并且 mem_fun_ptrs 无论如何都关闭了。

从 [SKJJ12] 第 9 页开始,我认为该函数以及调用堆栈上的所有函数或函数对象也需要标记restrict(amp)并实现该概念。

[SKJJ12] Sharlet, Kunze, Junkins Joshi 
Shevlin Park: Implementing C++ AMP with Clang/LLVM and OpenCL
http://llvm.org/devmtg/2012-11/Sharlet-ShevlinPark.pdf
于 2014-07-23T17:26:57.853 回答
0

假设我们有:

template <typename T, typename Func>
void Foo( const concurrency::array_view<const T>& avParam, Func f ) 

int f(int x) restrict(amp) {return x+2;}

然后尝试:

Foo( avParam, [](int x) restrict(amp){ return f(x); } );`

它不是指向 的函数指针f,而是创建一个不使用函数指针的 lambda。

我们可以自动化这个

#define AMP_OVERLOAD_SET(F) struct { \
  template<typename... Args> auto operator()(Args&&...args)const restrict(amp) \
  ->decltype( F(std::declval<Args>()...) ) \
  { return F( std::forward<Args>(args)... ); } \
}

static AMP_OVERLOAD_SET(f) amped_f; // declare an overload set object for `f`
Foo( vParam, amped_f ); // pass it to `Foo`

这可能会也可能不会起作用。

于 2014-07-24T19:23:14.983 回答