【问题标题】:C++, overloding functions, templatesC++,重载函数,模板
【发布时间】:2021-11-09 13:10:18
【问题描述】:

我想问是否可以为返回双精度的算术类型和返回 valarray 的容器(数组、向量、valarray 等)编写重载函数。简单的例子

template<typename T> 
double foo(T x) { 
  return x; 
}
 
template<typename T> 
std::valarray<double> foo(T const &arr) {
  std::valarray<double> valarr(1,1); 
  return valarr; 
}

结果我得到了预期的消息:对“foo”的调用不明确。有没有可能写出这样的函数?

我非常感谢所有的 cmets。

【问题讨论】:

  • 之所以模棱两可,是因为编译器无法判断您打算将第二个实现的参数设为数组类型。
  • @user888379 是的,我知道,我不是在问这个。我的问题是:如何正确书写
  • 很公平 - 我看到 @Jarod42 已经提供了一个很好的答案,但我想确保你理解编译器消息的细微差别。

标签: c++ templates


【解决方案1】:

你可以使用C++20概念

#include <valarray>
#include <concepts>

template<typename T> 
  requires std::is_arithmetic_v<T>
double foo(T x) { 
  return x; 
}

template<std::ranges::random_access_range T>
  requires std::is_arithmetic_v<std::ranges::range_value_t<T>>
std::valarray<double> 
foo(T const& arr) {
  std::valarray<double> valarr(1,1); 
  return valarr; 
}

Demo.

【讨论】:

    【解决方案2】:

    您可以使用std::enable_if 来做您想做的事情,如下所示:

    #include <iostream>
    #include <string>
    #include <valarray>
    
    //overload for arthemtic types
    template<typename T>
    std::enable_if_t<std::is_arithmetic_v<T>, double> foo(T x)
    {
        std::cout<<"arithmetic version"<<std::endl;
        return x;
    }
    //overload for array
    template<typename T, std::size_t N>
    std::valarray<double> foo(T const (&arr)[N])
    {
        std::valarray<double> valarr(2,5); 
        std::cout<<"array version"<<std::endl;
        return valarr;
    }
    
    //overload for non-arthemtic types
    template<typename T>
    std::enable_if_t<!std::is_arithmetic_v<T>, T> foo(T x) //note the "!" in this version
    {
        std::cout<<"non-arithmetic version"<<std::endl;
        return x;
    }
    int main() {
      int arr[3] = {1,2,3};
        foo(arr);//uses array version
        foo(5); //uses arithmetic version
        int p= 0, *c = &p;
        
        foo("string");//uses array version
        foo(p);//uses arithmetic version
        foo(c); //uses non-arithmetic version
    } 
    

    以上程序的输出可见here

    【讨论】:

    • 请问为什么以前的版本会出现这个错误?是第一个和哪个函数之间的冲突?
    • @Wywana 这是主模板(第一个版本)和算术版本之间的冲突。此外,您可以通过为除算术类型以外的所有类型创建另一个版本来轻松解决这个问题。例如,您可以将另一个版本写为:template&lt;typename T&gt; std::enable_if_t&lt;!std::is_arithmetic_v&lt;T&gt;, T&gt; foo(T x) { std::cout&lt;&lt;"non-arithmetic version"&lt;&lt;std::endl; return x; } 注意上述版本中的!。这将为所有非算术版本选择。我现在已将其添加到我编辑的答案中。你可以去看看。
    【解决方案3】:

    对于 C 数组类型,它将是:

    template<typename T, std::size_t N>
    std::valarray<double> foo(T const (&arr)[N])
    {
        // ...
    }
    

    Demo

    【讨论】:

    • 感谢您的回答:)。我想写得更笼统一些,比如:array、valarray、vector等类型。
    • 那么C++17及以下的唯一方法就是为每种类型编写多个重载函数?
    • @Wywana:大多数概念用法都可以用 SFINAE 代替,以更详细的方式。
    猜你喜欢
    • 2010-09-18
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 2016-10-03
    相关资源
    最近更新 更多