将可变参数传递给模板函数时出现编译错误
我有以下模板方法:
template<typename T, typename... Args>
void register_scene(const std::string& name, Args&&... args) {
auto func = std::bind(&T::template create<Window*, Args&...>, std::placeholders::_1, std::forward<Args>(args)...);
_store_scene_factory(name, [=](Window* window) -> SceneBasePtr {
auto ret = func(window);
ret->set_name(name);
return ret;
});
}
基本上我所需要做的就是将可变Args
绑定到T::create
(它本身是一个静态可变参数模板方法),但允许在调用时单独填充第一个参数(窗口)。
上面的代码失败,出现以下错误
error: no match for call to ‘(const std::_Bind<std::shared_ptr<{anonymous}::SceneWithArgs> (*(std::_Placeholder<1>, const char*))(smlt::Window*&, const char (&)[4])>) (smlt::Window*&)’
auto ret = func(window);
~~~~^~~~~~~~
当像这样调用代码时:
manager.register_scene<SceneWithArgs>("test", "arg");
我不太了解错误,或者如何解决这个错误。
我最初通过简单地调用lambda中的create来解决这个问题,并且这对GCC 4.9和更高版本起作用,但是我必须保持与GCC 4.8.4的兼容性,并且存在一个防止在lambda :()内使用可变参数的错误:
UPDATE
OK,因此添加std :: decay(如注释中所示)并未完全解决问题,第一个参数一直推演到Window*&&
而不是Window*
,但实际上指定了func
的类型(例如std::function<SceneBasePtr (Window*)>
)而不是使用auto
编译的东西。
我不确定这是为什么......
您没有显示create
声明,但我认为它看起来如下所示:
template <typename... Args>
static SceneBasePtr create(Args&&...);
看上去不错。 您使用转发引用,以便编译器可以推断参数的确切类型。 只要编译器推断出这些类型,这就行得通了。 然而...
&T::template create<Window*, Args&...>
在这里,你明确地实例化函数模板。 也就是说,编译器将不再推断这些类型,而是会用您提供的模板参数替换模板参数。 这些模板参数是什么?
template <typename T, typename... Args>
void register_scene(const std::string& name, Args&&... args);
//...
manager.register_scene<SceneWithArgs>("test", "arg");
第一个是显式传递的,它是Window*
,这个很明显。 现在Args...
- "test"
和"arg"
是原始字符串文字,它们的对应类型分别是const char[5]
和const char[4]
。 然后, Args...
(扣除过程之后)变为const char(&)[5]
和const char(&)[4]
。 那么当你用这些类型实例化create
时,现在会发生什么? 你将会得到如下的声明:
static SceneBasePtr create(Window*&&, const char(&)[5], const char(&)[4]);
请注意,引用合并规则将第一个参数转换为r值引用,其余为l值引用。
std::bind
也会导出类型。 但是, std::bind
会希望存储参数,以便稍后可以重用它们。 问题是std::bind
不能存储const char[5]
。 相反,它会衰减每个参数的类型。 这意味着每个原始字符串文字将变为const char*
,并且将作为此类型的l值参数传递给绑定函数,并且这与手动实例化的create
不匹配。 window
参数也有类似的问题。 它被推断为一个l值,但是,手动实例化的create
函数需要一个r值。
最好不要明确指定函数模板的模板类型。 如果由于某些原因(bug?),你不能在lambda中使用args...
,你可以生成一个合适的create
签名:
&T::template create<Window*&, typename std::decay<Args>::type&...>
// ~^~ ~~~~~~~~~^
结束于:
static SceneBasePtr create(Window*&, const char*&, const char*&);
链接地址: http://www.djcxy.com/p/51585.html
上一篇: Compilation error when passing variadic args to a template function