提问人:pic32cpp 提问时间:10/28/2023 最后编辑:pic32cpp 更新时间:10/28/2023 访问量:68
专用可变参数模板成员函数时出现的问题
Problems when specializing variadic template member function
问:
我有以下状态机示例,该示例使用枚举来专门化具有可变参数包的模板方法。当我通过引用传递属性 (Properties&) 而不是按值传递属性 (Properties) 时,为什么不调用第二个专用化?
enum class State
{
StateA,
StateB
};
enum class Event
{
Event1,
Event2
};
struct Properties
{};
template <typename TState, typename TEvent>
struct StateMachine
{
template <TState tstate, TEvent tevent, typename ...TArgs>
void enter(TArgs ...args)
{
std::cout << "Default" << std::endl;
}
};
template <>
template <>
void
StateMachine<State, Event>::enter<State::StateA, Event::Event1>(int i)
{
std::cout << "Specialized 1" << std::endl;
}
template <>
template <>
void
StateMachine<State, Event>::enter<State::StateA, Event::Event2>(Properties& properties)
{
std::cout << "Specialized 2" << std::endl;
}
int main(int argc, char* argv[])
{
StateMachine<State, Event> sm;
int value = 123;
sm.enter<State::StateA, Event::Event1>(value);
Properties properties;
sm.enter<State::StateA, Event::Event2>(properties);
}
我期待输出:
Specialized 1
Specialized 2
但得到:
Specialized 1
Default
当我按值传递属性时,它可以正常工作。这是一个完美的转发问题吗?如何解决?
答:
3赞
user12002570
10/28/2023
#1
问题在于,只有通用版本(又名主模板)参与重载,并且在主模板中,参数由值获取,而在属性的专用模板中,参数由左值引用获取。也就是说,在主模板中,第三个参数被推导出为 while 对于专业化,它是 。enter
Properties
Properties&
如何解决?
这意味着有两种方法可以解决这个问题。您可以进行左值引用,也可以显式传递为第三个参数,如下所示。args
Properties&
方法 1
在这里,我们通过将 更改为 来对 non-const 进行左值引用。请注意,您也可以将其作为对 const 的左值引用,因为不会更改任何内部结构。args
TArgs ...args
TArgs& ...args
enter
template <typename TState, typename TEvent>
struct StateMachine
{
template <TState tstate, TEvent tevent, typename ...TArgs>
//------------------v-------------------->added lvalue ref
void enter(TArgs& ...args)
{
std::cout << "Default" << std::endl;
}
};
template <>
template <>
void
//-----------------------------------------------------------------v-->lvalue ref
StateMachine<State, Event>::enter<State::StateA, Event::Event1>(int& i)
{
std::cout << "Specialized 1" << std::endl;
}
int main(int argc, char* argv[])
{
StateMachine<State, Event> sm;
Properties properties;
sm.enter<State::StateA, Event::Event2>(properties); //prints specialized 2
}
方法 2
第二种方式是显式传递第三个参数。Properties&
int main(int argc, char* argv[])
{
StateMachine<State, Event> sm;
Properties properties;
//-----------------------------------------vvvvvvvvvvv--->explicitly pass third argument
sm.enter<State::StateA, Event::Event2, Properties&>(properties); //prints specialized 2
}
评论
sm.enter<State::StateA, Event::Event2, Properties&>(properties);
TArgs...
Properties&
Properties