为什么这个可变函数调用不明确?

时间:2014-12-29 00:31:19

标签: c++ c++11

  template<typename FilterComponent, typename ...FilterComponents>
  std::bitset<components_count> component_impl(std::bitset<components_count> &b){
    b.set(FilterComponent::get_id());
    return component_impl<FilterComponents...>(b); //ambiguous
  }
  template<typename FilterComponent>
  std::bitset<components_count> component_impl(std::bitset<components_count> &b){
    b.set(FilterComponent::get_id());
    return b;
  }
  template<typename ...FilterComponents>
  std::bitset<components_count> component_mask(){
    std::bitset<components_count> b;
    component_impl<FilterComponents...>(b);
    return b;
  }

为什么这个函数调用不明确?我想把它称为component_mask<Foo,Bar,Baz>();

error: call to member function 'component_impl' is ambiguous
    return component_impl<FilterComponents...>(b);

2 个答案:

答案 0 :(得分:5)

FilterComponents...为空或只有一个元素时,存在歧义,因为两个函数模板同样可行。您可以向第一个模板声明添加第二个模板参数以解决歧义(如R Sahu那样)。您还可以将参数解压缩到初始化列表中以获得相同的效果:

template<typename... FilterComponents>
std::bitset<components_count> component_impl(std::bitset<components_count>& b)
{
    using discard = int[];
    (void)discard{ 0, (b.set(FilterComponents::get()), void(), 0)... };
    return b;
}

第一个0和尾随0用于补偿空参数包并用整数填充列表,从而丢弃void()类型。 void()“删除”set()的返回值,从而阻止可能使用其返回类型的重载operator,()(我们知道std::bitset::set()没有,但是当你处理一般情况时,使用它会很有帮助。)

这也消除了第二次重载以帮助递归的需要。

答案 1 :(得分:2)

当使用一个类型名称调用component_impl时,它是不明确的。第一个版本与空的typename包匹配。第二个版本也是匹配。

将可变参数模板版本更改为在typename包之前有两个类型名称。这将消除这两个功能的歧义。

template<typename FilterComponent1, typename FilterComponent2, typename ...FilterComponents>
std::bitset<components_count> component_impl(std::bitset<components_count> &b){
   b.set(FilterComponent1::get_id());
   return component_impl<FilterComponent2, FilterComponents...>(b);
}