【问题标题】:Why is this variadic function call ambiguous? [duplicate]为什么这个可变参数函数调用不明确? [复制]
【发布时间】:2014-12-29 09:21:27
【问题描述】:
  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&lt;Foo,Bar,Baz&gt;();

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

【问题讨论】:

  • 请测试用例...... 为什么我必须在每个问题上都要求测试用例?为什么很难理解它的重要性?为什么没有人在之前在互联网上发布它们?!啊!!!
  • @LightnessRacesinOrbit 好的,给我一点时间。
  • FilterComponents只有一个元素时,两个函数模板都可以用完全相同的模板参数实例化。
  • @0x499602D2 谢谢,有道理。
  • @LightnessRacesinOrbit:这就是问题应该包含 complete 错误消息的原因。当然,查看完整的消息,可能不需要这个问题。 IDE 通过提供一个“错误列表”窗口来截断第一个换行符处的错误信息,从而造成巨大的伤害。

标签: c++ c++11


【解决方案1】:

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() 没有,但当您处理一般如果使用它会有所帮助)。

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

【讨论】:

  • 我猜它完全不需要单独的辅助函数。
  • 很好的解决方案。对0void() 的解释不会出错!
  • 第一个 0 应该在包扩展之外。
  • 您取出的void() 在这里确实没有必要,但这是一个很好的通用提示,我认为您很高兴包括在内:它确保内置的, 是无论b.set 是如何声明的,都可以使用,因为没有自定义operator, 可以采用void 类型的参数。这里没有必要,因为已知b.set 的返回类型没有任何重载的operator,,但如果将此答案扩展为调用返回其他类型的其他方法,这将很有用。
  • @hvd 谢谢,我会加回来的。
【解决方案2】:

component_impl 用一个类型名调用时,它是模棱两可的。第一个版本与空类型名包匹配。第二个版本也很匹配。

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

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);
}

【讨论】:

    猜你喜欢
    • 2014-11-18
    • 2016-05-18
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多