【问题标题】:Template expansion fails when passed Reference?通过引用时模板扩展失败?
【发布时间】:2013-09-23 17:47:04
【问题描述】:

我正在围绕 Lua 的 C Api 编写一个简单的包装器,并让函数接受 lua_State& 而不是指针。但是,当我尝试传递 lua_State* 值时,我必须取消引用它以通过引用传递。扩展为的模板具有 func sig,其中 vm 按值而不是引用传递。

由于可以在没有完整定义的情况下使用对象的引用和指针,有没有一种方法可以将指针值转换为只需要类型的前向声明的引用值?

编辑: 在玩了一些代码之后。取消引用适用于其中一个函数调用,但在另一个函数调用上失败。

namespace Vm {

template<typename VM, typename T>
void push( VM vm, T value );

// If this function isn't here, push will fail too.
template<typename T>
void push( lua_State& luaState, T value ) {
    Vm::push( luaState, value );
}

template<>
void push( lua_State& luaState, double value ) {
    lua_pushnumber( &luaState, value );
}

template<typename VM>
void pop( VM vm, Uint32 nIndices );

template<>
void pop( lua_State& luaState, Uint32 nIndices ) {
    lua_pop( &luaState, nIndices );
}

}


int main( int argc, char** argv )
{
    lua_State* luaState = luaL_newstate();
    luaL_openlibs( luaState );
    Vm::push( *luaState, (double)1.2f ); // This works fine.
    Vm::pop( *luaState, 1 ); // This generates error.
}

编译器错误:

error: invalid use of incomplete type ‘struct lua_State’
error: forward declaration of ‘struct lua_State’
error:   initializing argument 1 of ‘void Vm::pop(VM, Uint32) [with VM = lua_State; Uint32 = unsigned int]’

【问题讨论】:

  • 你使用哪种演员阵容?
  • 你描述的应该没问题;您不需要类型定义来取消引用指针并获取引用:ideone.com/yxrt94。你能发布一些给出错误的示例代码吗?
  • 我正在寻找某种类型的演员,但我刚刚找到了 reinterpret_cast() 这可能就是我正在寻找的。​​span>
  • @syam:我们应该建议弃用 reinterpret_cast&lt;...&gt;() 并用 this_is_not_the_cast_you_are_looking_for&lt;...&gt;() 替换它。
  • @DietmarKühl i_take_full_responsibility_of_whatever_bug_ensues&lt;...&gt;() 我认为更像是一种威慑。责任使人害怕。 ;)

标签: c++ templates lua


【解决方案1】:

相关部分是 5.3.1 [expr.unary.op] 第 1 段:

一元*运算符执行间接:应用它的表达式应该是一个指向对象类型的指针,或者是一个指向函数类型的指针,结果是一个左值,指向表达式指向的对象或函数.如果表达式的类型是“指向 T 的指针”,则结果的类型是“T”。 [ 注意:指向不完整类型(除了 cv void)的指针可以被取消引用。这样获得的左值可以以有限的方式使用(例如,初始化引用);此左值不得转换为纯右值,见 4.1。 ——尾注]

也就是说,您可以取消引用指向不完整类型的指针以获取对不完整类型的引用。您将无法使用由此获得的参考做很多事情。基本上,您将无法做任何需要定义不完整类型的事情。

【讨论】:

  • 好的,所以我没有做任何需要定义的事情,因为我只是将它传递给 Lua 的 Api,然后使用它的定义......
【解决方案2】:

使用引用时不需要完整的定义,但你 当您实例化您的 VMlua_State 的模板。并且值参数确实需要 在调用站点和函数定义处完成声明。

在您的代码中,Vm::push 专门用于 lua_State&amp;double, 所以你得到了Vm::push( *luaState, (double)1.2f );的专业化 (但为什么是(double)1.2f,而不仅仅是1.2?),所以你得到了 专业化。 Vm::pop 没有专门用于 但是,lua_State&amp;int,因此您获得了 模板,它使用按值传递。 (我假设Uint32不是int 的类型定义。)

【讨论】:

  • 我向 Uint32 添加了显式转换,我想我应该在这里更新它。如果您查看错误,Vm::pop 被解析为 (lua_State, Uint32),并且没有引用属性。
【解决方案3】:

将 Vm::pop 的定义更改为在 VM 参数上具有引用属性似乎可以解决问题:

namespace Vm {    
template<typename VM>
    void pop( VM& vm, Uint32 nIndices );
}

除非你是一个顽固的函数式程序员,否则每次都复制 VM 没有任何意义。我仍然不明白为什么调用解析为 lua_State 而不是 lua_State&,并在 Vm::push 包装函数中正确推断(这个设法提供了更多信息..不知何故..)。哦-嗯,现在运行良好。

感谢您的帮助!

【讨论】:

    猜你喜欢
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多