【问题标题】:Can I define a type alias depending on runtime conditions in C++?我可以根据 C++ 中的运行时条件定义类型别名吗?
【发布时间】:2011-05-27 04:50:34
【问题描述】:

我正在开发一个 OpenCL 程序,它使用“cl_khr_byte_addressable_store”扩展名来允许在内核代码中进行字节级写入;为了让我的程序也能在不支持扩展的 GPU 上运行,我需要检查扩展是否可用,并在不支持的平台上使用 int 类型而不是 char

在内核代码中,我可以简单地添加以下 sn -p 并在整个内核代码中使用writeable_type;如果扩展可用,则 OpenCL 内核编译器会自动添加预处理器定义 cl_khr_byte_addressable_store

/* kernel.cl */
#ifdef cl_khr_byte_addressable_store
    typedef char writeable_type;
#else
    typedef int writeable_type;
#endif

f() {
    writeable_type x = 1;
}

在我的主机代码中,我没有那个预处理器定义,并且(据我所知)检查扩展是否可用只能在运行时完成:

/* host.cpp */
void execute() {
    std::string extensions;
    this->opencl->getExtensions(extensions);
    if (extensions.find("cl_khr_byte_addressable_store") != std::string::npos) {
        // extension is available
        typedef cl_char writeable_type;
    }
    else {
        // extension is not available
        typedef cl_int writeable_type;
    }
    writeable_type x = 1;
}

这就是我的问题;因为 typedef 是在编译时解析的,并且只在定义它们的块内有效,所以上面的示例不起作用。

是否有可能以某种方式做到这一点?


感谢 rlc、Neil Butterworth 和 talonmis 让我走上了正确的道路!结果证明我的问题的解决方案相当简单:

/*host.cpp*/

void execute() {
   bool extension_available = ...;  
   if (extension_available)
       this->_execute<cl_char>();
   else
       this->_execute<cl_int>();
}

template <typename writeable_char>
void _execute() {
    writeable_type x = 1;
    // ...
}

【问题讨论】:

    标签: c++ opencl


    【解决方案1】:

    如果你的所有代码都在一个公共函数与类型无关的类中,你可以这样做:

    // assuming these are defined in OpenCL somewhere
    typedef char cl_char;
    typedef int cl_int;
    
    // the public part of the base class cannot use the 
    // writable size because it cannot know the size of the writable type
    class Base
    {
    public :
        /* stuff */
        virtual void doStuff() = 0;
        /* more stuff */
    };
    
    // the writable type's size is known in this class and is
    // either cl_char or cl_int, so this is where data that has
    // to know the size will be carried around, and where API calls
    // that need to know the exact writable type go.
    // Code that is agnostic of the writable type need not be here
    // (but can be)
    template < typename WritableType >
    class Derived : public Base
    {
    public :
        virtual void doStuff()
        {
            /* do stuff */
        }
    };
    
    int main()
    {
        bool condition(false);
        /* magic to check for type size here */
        // once you get here, you know what the writable type is going to be,
        // so you can create an instance of the derived class accordingly
        Base *o;
        if (condition)
        {
            o = new Derived< cl_char >;
        }
        else
        {
            o = new Derived< cl_int >;
        }
        // as of here, you no longer need to know what the writable type
        // is because that knowledge is encapsulated in the object o
        o->doStuff();
    }
    

    即模板化根据您在运行时需要的类型执行所有操作的类,并使用您需要的版本。

    【讨论】:

    • 如果它们“与类型无关”,为什么首先要有类型?
    • 我说公共函数需要与类型无关,因为这将允许它们被重载。类型本身需要在类的逻辑中使用(在私有部分中)
    • 请将 OP 的 typedef 合并到您的解决方案中
    • @Neil 我已经从 OP 的代码(cl_intcl_char)中添加了 typedef,并添加了一堆 cmets 来解释代码的作用。 -- HTH
    • 请说明您的代码在运行时如何选择正确的类型。任何人都可以写出糟糕的 cmets,如果您删除它们,您的答案会更加清晰(但仍然是错误的)。谁在投票????
    【解决方案2】:

    在编译时必须知道 C++ 中的所有类型 - 此规则不可能有任何例外(对于 C 也是如此)。考虑到语言的定义方式,在运行时重新定义类型的尝试根本没有意义。如果你发现你认为你需要这样做,那么你的设计就有问题。

    【讨论】:

    • 该设计几乎是由 OpenCL 规范预定义的,也就是说,我无能为力。当然,我可能会误解它,在这种情况下,我将不胜感激有关如何“正确”处理可选扩展的任何提示...
    • @Ben 我对您的具体问题领域一无所知,但我认为一种解决方案是在运行时创建类型的 instances
    【解决方案3】:

    您必须对目标 OpenCL 平台使用的选项进行运行时检查并做出相应的反应。使用CL_PLATFORM_EXTENSIONS 查询调用clGetPlatformInfo,您将返回一个字符数组,可以对其进行解析以检查是否支持cl_khr_byte_addressable_store。然后相应地选择具有整数或字符类型的路径。

    大多数供应商 SDK 都包含某种设备查询应用程序,其中包含 clGetPlatformInfo 使用示例。你应该可以从那里抄一些代码。

    【讨论】:

    • 这正是我已经在做的事情(隐藏在opencl-&gt;getExtensions()):-) “运行时检查”位是我问题的核心......
    • 哦,好的。难道你不能只使用类型作为模板参数,在某处实例化这两种情况,然后只使用 clGetPlatformInfo() 的结果来选择要调用的实例吗?
    【解决方案4】:

    您试图在编译时根据运行时某物的值来更改变量。除非您将编译时提前到运行时,例如使用 JIT 或解释,或者发明时间旅行,否则物理定律决定了您想要什么是不可能的。

    当然,你也可以使用继承和虚函数来移除依赖。

    【讨论】:

    • “试图在编译时改变一个变量”——这就是他们的目的。 (您的意思是“试图在编译时更改变量的 type”吗?)
    猜你喜欢
    • 2020-07-25
    • 1970-01-01
    • 2016-04-10
    • 2021-03-23
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 2020-05-31
    • 2017-01-30
    相关资源
    最近更新 更多