【问题标题】:How does template function work with multiple typenames which may share an intersection?模板函数如何与可能共享交集的多个类型名一起使用?
【发布时间】:2025-12-06 20:30:02
【问题描述】:

我是 C++ 新手,目前正在尝试了解模板函数的工作原理。首先我想添加两个相同类型的数值,这很容易理解。

template <typename T>
T add(T a, T b){return a+b;}
int main(){
    float a_f=2.5;float b_f=1.5;float c_f;
    int a_i=2;int b_i=1;int c_i;
    c_f = add(a_f, b_f);
    c_i = add(a_i, b_i);
    return 0;
}

接下来我想添加两个不同且相等类型的数字。我天真的假设是这样的:

template<typename R, typename S, typename T>
R add(S a, T b){return a+b;}
int main(){
    float a=3.2; int b=2;
    auto result1 = add(a,b);    // error: no matching function for call to ‘add(float&, int&)’
    auto result2 = add(a,a);    // error: no matching function for call to ‘add(float&, float&)’
    auto result3 = add(b,b);    // error: no matching function for call to ‘add(int&, int&)’
    return 0;
}

我知道这种方法是不正确的,因为类型名共享一个关于数据类型的交集,因此声明本身不可能是正确的。

如何实现一个简单的 add() 函数,将两个数值相加,而不考虑类型?

【问题讨论】:

    标签: c++ templates generic-programming


    【解决方案1】:

    问题不在于交叉点,而在于它无法推断出R。在

    template<typename R, typename S, typename T>
    R add(S a, T b){return a+b;}
    

    没有什么可以告诉编译器R 应该是什么。它不是从您将结果分配给的变量中推导出来的,并且您没有指定它,因此它没有可以执行的有效调用。要解决此问题,您可以摆脱 R 并使用 auto 返回类型来为您推断它

    template<typename S, typename T>
    auto add(S a, T b){return a+b;}
    

    【讨论】:

      【解决方案2】:

      如何实现一个简单的add() 函数,将两个数值相加,而不管其类型如何?

      在 C++14 中:

      template<class T, class U>
      auto add(T t, U u) {
          return t + u;
      }
      

      上面,返回值的类型是从表达式t + u的类型推导出来的。

      C++11 不推断返回类型,但允许尾随返回类型,因此 C++11 版本是:

      template<class T, class U>
      auto add(T t, U u) -> decltype(t + u) {
          return t + u;
      }
      

      【讨论】:

      • 啊哈,这很有道理,解决了我的问题。你能解释一下为什么你使用'class'而不是'typename'吗?
      • @One3Three7 class 的类型更短,classtypename 在此上下文中没有区别。
      • 您可以在{ 之前添加-&gt; decltype(t + u) 以实现C++11 兼容性。
      • ... 或 -&gt; std::common_type&lt;S,T&gt;::type
      • @One3Three7 我更喜欢typename 并且希望其他人这样写,因为它可以更好地表达一个人的意图。可读性很重要。
      【解决方案3】:

      你想要的是推断返回类型。但是,类型模板参数的类型推导只适用于函数参数。

      尽管类型名不是执行此操作的正确工具,但 C++ 提供了其他方法来推断类型。

      使用自动

      您可以简单地将auto 放在那里,让编译器从返回类型中推断:

      template<typename S, typename T>
      auto add(S a, T b){ return a + b; }
      

      使用尾随返回类型

      如果您想更明确地说明函数的返回类型,也可以使用尾随返回类型:

      template<typename S, typename T>
      auto add(S a, T b) -> decltype(a + b) { return a + b; }
      

      【讨论】: