【问题标题】:Overloading functions with concepts用概念重载函数
【发布时间】:2021-05-27 15:41:19
【问题描述】:

(我正在学习概念和模板,如果我对某些事情有很大的错误,请纠正我。)我有一个将概念作为参数的函数。我现在正试图重载这个需要更具体概念的函数。那会做“更具体的事情”或调用不太具体的函数。

template<typename T>
concept Concept1 = ...;

template<typename T>
concept MoreSpecificConcept = ...;
    Concept1 <T> &&
    ...;

//...
void someFunc(const Concept1 auto& x)
{
  //do general stuff
}

void someFunc(const MoreSpecificConcept auto& x)
{
  if(...)
  {
    //do specific stuff
  }
  else
  {
    //do the more general thing:

    // Problem. Trying to call itself:
    someFunc(x);
  }
}

有没有办法明确告诉编译器要调用哪个重载(例如 someFunc&lt;Concept1&gt;(x) 不起作用),还是仅取决于传递对象的类型?可以说我不能将x 转换为更通用的类型,并且更通用的功能/概念不知道这个更具体的功能/概念,因此他们不能通过约束排除它。 编辑:这些函数应该在同一个(全局)命名空间内。

【问题讨论】:

  • 作为work-araound,仍然将//do general stuff提取到另一个名称不同的函数中。
  • 另一种可能的解决方法是编写一个包装器,它接受Concept1 并通过转发到包装器来满足Concept1:所以someFunc(asConcept1{x});

标签: c++ templates overloading c++20 c++-concepts


【解决方案1】:

通常的解决方法是使用单独的辅助函数:

void somefunc(const Concept1 auto& x) {
  // general stuff
}

void somefuncSpecific(const Concept1 auto& x) {
  somefunc(x);
}

void someFuncSpecific(const MoreSpecificConcept auto& x)
{
  if(...)
  {
    //do specific stuff
  }
  else
  {
    //do the more general thing:
    somefunc(x);
  }
}

另一个没有分离功能的解决方法是使用if constexpr

void someFuncSpecific(const Concept1 auto& x)
{
  if constexpr(MoreSpecificConcept<decltype(x)>)
  {
    if (...)
    {
      //do specific stuff

      // skip the rest:
      return;
    }
  }
  //do the more general thing:
  somefunc(x);
}

【讨论】:

  • 谢谢!我看到的问题是,如果someFunc(const Concept1 auto&amp; x) 和一些已经存在的调用它的代码无法更改,那么用不同的名称包装它并不是理想的解决方案。 (不过,目前还没有这样的代码,因为它只是练习。)
  • 是的,无法更改的代码总是会导致代码变差。我建议使用您可以更改的代码。如果不能,则创建一个调用旧函数的新函数,除非有特定操作。
【解决方案2】:

如果可能(主要取决于这两个概念),另一种解决方法是创建仅满足 Concept1 但不满足 MoreSpecificConcept 的包装器:

template <Concept1 T>
struct AsConcept1
{
    T& t;

    // operations to satisfy Concept1 (but not MoreSpecificConcept)
    // using some_type = typename Concept1::some_type
    // void bar() { t.bar(); }
    // ...
};

然后你可能会这样做

void someFunc(const MoreSpecificConcept auto& x)
{
    if (...) {
        // do specific stuff
    } else {
        // do the more general thing:
        someFunc(AsConcept1{x});
    }
}

【讨论】:

    【解决方案3】:

    这是我的Minimal Complete Verifiable Example版本

    #include <iostream>
    #include <type_traits>
    
    template <typename T>
    concept aritmetic = std::is_arithmetic_v<T>;
    
    template <typename T>
    concept real = std::is_floating_point_v<T>;
    
    template<aritmetic T>
    void foo(T x)
    {
        std::cout << __PRETTY_FUNCTION__ << " x + 1 = " << x + 1 << '\n';
    }
    
    #ifdef HAS_OVERLOAD
    void foo(real auto x)
    {
        std::cout << __PRETTY_FUNCTION__ << " x / 2 = " << x / 2 << '\n';
    }
    #endif
    
    int main()
    {
        foo(1);
        foo(1.1);
    
        return 0;
    }
    

    这是我的idea how to fix it

    #include <iostream>
    #include <type_traits>
    
    template <typename T>
    concept aritmetic = std::is_arithmetic_v<T>;
    
    template <typename T>
    concept real = std::is_floating_point_v<T>;
    
    template<aritmetic T>
    void foo(T x) requires (!real<T>)
    {
        std::cout << __PRETTY_FUNCTION__ << " x + 1 = " << x + 1 << '\n';
    }
    
    void foo(real auto x)
    {
        std::cout << __PRETTY_FUNCTION__ << " x / 2 = " << x / 2 << '\n';
    }
    
    int main()
    {
        foo(1);
        foo(1.1);
    
        return 0;
    }
    

    我认为这个版本很好很干净:不需要额外的功能或者这个讨厌的if

    【讨论】:

      猜你喜欢
      • 2020-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      相关资源
      最近更新 更多