【问题标题】:Ambiguous call to variadic template function with no parameters?对没有参数的可变参数模板函数的模糊调用?
【发布时间】:2018-03-20 08:53:52
【问题描述】:

运行时:

template <typename T>
struct CodeByType
{
    static const int32_t Value = 7;
};

template <>
struct CodeByType<int>
{
    static const int32_t Value = 1;
};

template <typename Arg, typename... Args>
int32_t Sum()
{
    // The compiler complains on this line
    return Sum<Arg>() + Sum<Args...>();
}

template <typename Arg>
int32_t Sum()
{
    return CodeByType<Arg>::Value;
}

int main()
{
    auto sum = Sum<int, char, double>();
}

我明白了:

错误 C2668 'Sum':对重载函数的模糊调用

谁能解释一下为什么以及如何克服它?

这看起来与下面的代码非常相似,它确实可以编译,所以我想这与Sum 不接受任何实际参数有关。

template <typename T>
T adder(T first) {
    return first;
}

template<typename T, typename... Args>
T adder(T first, Args... rest) {
    return first + adder(rest...);
}

int main()
{
    auto sum = adder(1, 7);
}

【问题讨论】:

    标签: c++ c++11 variadic-templates


    【解决方案1】:

    我对模板机制的记忆很旧,但如果我没记错的话,它们的信息会在编译过程的某个时刻被删除。

    我的猜测是,在第二种情况下,函数的区别不是通过模板类型的差异,而是通过参数的差异。

    在你的情况下,你没有参数,所以去掉模板信息,两个重载版本是相等的,当你调用它时它无法区分它们。

    【讨论】:

      【解决方案2】:

      如果您将代码简化为:

      Sum<int>();
      

      您会收到更有用的错误消息:

      31 : <source>:31:16: error: call to 'Sum' is ambiguous
          auto sum = Sum<int>();
                     ^~~~~~~~
      17 : <source>:17:9: note: candidate function [with Arg = int, Args = <>]
      int32_t Sum()
              ^
      24 : <source>:24:9: note: candidate function [with Arg = int]
      int32_t Sum()
              ^
      1 error generated.
      

      因此更清楚的是,Args = &lt;&gt; 的第一个重载与第二个重载之间存在重载歧义。两者都是可行的。

      人们可能会认为是解决方案的专业化:

      template <typename Arg>
      int32_t Sum<Arg>()
      {
          return CodeByType<Arg>::Value;
      }
      

      如果标准允许的话,这确实可以解决问题。不允许部分函数特化。

      C++17 解决方案:

      这是最优雅的解决方案:

      constexpr if 救援:

      template <typename Arg, typename... Args>
      int32_t Sum()
      {
          if constexpr(sizeof...(Args) == 0)
            return CodeByType<Arg>::Value;
          else
            return Sum<Arg>() + Sum<Args...>();
      }
      

      C++14 解决方案

      我们使用 SFINAE 来启用/禁用我们想要的功能。请注意函数定义顺序必须颠倒。

      template <typename Arg, typename... Args>
      auto Sum() -> std::enable_if_t<(sizeof...(Args) == 0), int32_t>
      {
            return CodeByType<Arg>::Value;
      }
      
      
      template <typename Arg, typename... Args>
      auto Sum() -> std::enable_if_t<(sizeof...(Args) > 0), int32_t>
      {
            return Sum<Arg>() + Sum<Args...>();
      
      }
      

      C++11解决方案

      只需将std::enable_if_t&lt;&gt; 替换为typename std::enable_if&lt;&gt;::type

      【讨论】:

        【解决方案3】:

        在 c++17 中,它只是

        template <typename... Args>
        int32_t Sum()
        {
            return (CodeByType<Args>::Value + ...); // Fold expression
        }
        

        在 C++11 中,你可以这样做:

        template <typename... Args>
        int32_t Sum()
        {
            int32_t res = 0;
            const int32_t dummy[] = {0, (res += CodeByType<Args>::Value)...};
            static_cast<void>(dummy); silent warning about unused variable
            return res;
        }
        

        【讨论】:

        • 我迷失了为什么他的解决方案不起作用,我忽略了他最终想要做的事情。非常好的解决方案。
        • @bolov: bracco23 解释它:根据参数比较选择“最佳”函数。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-02
        • 1970-01-01
        • 2013-05-21
        相关资源
        最近更新 更多