如何在Metal内核中访问C++引用或指针的成员?

5
每当我尝试实际使用来自任何地址空间(常量、设备或线程)的引用时,总是会出现相同的错误。这无法编译,并且会产生奇怪的错误:
struct Foo {
    int getter() const {
        return 1;
    }
};

void use_foo(constant Foo& foo) {
    int x = foo.getter(); // error here
}

kernel void test_kernel(constant Foo& foo [[buffer(0)]]) {
    use_foo(foo);
}

错误信息为:

无法使用类型为 'const常量 Foo' 的表达式初始化类型为 'const Foo' 的对象参数

用任何其他内存地址限定符替换 `constant` ,都是相同的一般性错误。不管是直接传递到内核中的引用还是由函数创建的线程本地引用 - 由于这个错误,我实际上无法以任何方式使用这些引用。它们是否是 const 或非 const 引用也没有关系。
唯一的解决方法就是拷贝 `Foo` 而不是尝试使用对它的引用。我从来没有理解过这个奇怪的错误。我还尝试将参数作为 `constant const Foo &` 以及其他尝试和错误。
有人能指导如何实际使用引用吗?
如果我切换到使用指针而不是引用,我会得到类似的错误。

enter image description here

从这个开始:
struct Foo {
    int getter() const {
        return 1;
    }
};

void use_foo(constant const Foo* const foo) {
    int x = foo->getter(); // error here
}

kernel void test_kernel(constant Foo* foo [[buffer(0)]]) {
    use_foo(foo);
}

类似的尝试在不同地方使用 const 或不使用并没有任何区别。


1
只是猜测,但是是否可能限定方法 int getter() const constant - jtbandes
1
哇,@jtbandes,那确实是一个好猜测,我之前没有尝试过。而且它起作用了!你以前见过这种问题吗?你怎么知道要尝试这个呢?唯一的问题是,如果成员函数不会在“常量const”引用上使用,那么我需要一个相同的重载,没有添加“常量”,否则会出现类似的错误。但这已经解决了,太神奇了。 - johnbakers
1
这太惊人了。@jtbandes,推理得好! - warrenm
1
还有一个想法:值得为你收到的糟糕错误消息提交一个错误报告,因为它并没有真正解释实际的问题。 - jtbandes
1
继续独白:实际上,你收到的错误消息似乎是在我链接的补丁之前的代码版本中产生的。很可能Metal编译器作为Clang的分支进行维护,并从未合并过我2017年的更改。我不禁想知道,如果他们采用了我的补丁,这个错误消息会不会更好,因为编译器可能会提醒他们在添加新类型的“BadConversionSequence”时更新那段代码 ;) - jtbandes
显示剩余3条评论
1个回答

4

您的成员函数资格通常必须与被调用对象的类型相匹配。如果您想在一个const常量对象上调用这样的方法,可以将您的方法标识为这样:

    int getter() const constant {
        return 1;
    }

金属着色语言规范(§4)指出:“任何指针或引用的变量必须声明为[device、constant、thread、threadgroup或threadgroup_imageblock]”。重要的是要理解成员函数的this参数是一个指针,基本上是一个不可见的函数参数,函数的限定符影响该指针的类型。实际上,您正在声明int getter(const constant Foo * this)


1
非常感谢您的评论,我从中学到了很多! - johnbakers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接