【问题标题】:How to avoid an invalid overload from the std library?如何避免 std 库中的无效重载?
【发布时间】:2020-09-15 17:37:11
【问题描述】:

在我正在使用的 C++14 项目中

#include <algorithm>
using std::max;            // for max(a,b)

但我还想提供一个max() 函数,它接受任意数量的参数(相同类型)。为此,我添加了

template<typename T, typename...A>
constexpr inline T const& max(T const&x, T const&y, A...&&z)
{
    return max(max(x,y), std::forward<A>(z)...);
}

但是在打电话时

double x,y,z;
...
auto m = max(x,y,z);

编译器试图代替我的重载使用

namespace std {
template< class T, class Compare >
constexpr const T& max( const T& a, const T& b, Compare comp );
}

来自algorithm。我怎样才能避免这种情况(但仍提供预期的功能)?

(请注意,有一个question about variadic min/max,但它并不能解决我的问题,只需将名称更改为vmin/vmax。)

【问题讨论】:

  • std::max 有一个重载,它采用初始化列表。也许这对你有用? en.cppreference.com/w/cpp/algorithm/max
  • 不要做using std::max——到处使用显式命名空间解析。
  • @RetiredNinja 这不是一个解决方案,因为它没有提供预期的功能。同样适用于 wochran 的评论。
  • 需要注意的是,之所以调用std::max重载是因为double可以隐式转换为bool,这使得重载比解包参数包并继续扩展
  • @mkamerath 为什么是布尔值?

标签: c++ c++14 variadic-templates overload-resolution


【解决方案1】:

问题可以通过仅重载 3 个或更多参数的函数来解决,例如:

template<typename T, typename...A>
constexpr inline T const& max(T const&x, T const&y, T const&z, A&&...w)
{
    return max(max(x,y), z, std::forward<A>(w)...);
}

【讨论】:

  • 澄清一下:这是否可行,因为此模板的专业化(带有A = [] 的那些)被认为比标准库中的专业化更具体,因此在可能的情况下选择该模板?
  • @HTNW 我想是的。而且我还在阅读标准的[over.match.best]
【解决方案2】:

你没有。

要么停止 using std::max 并改为限定您的命名空间,要么将您的函数命名为其他名称。

【讨论】:

    【解决方案3】:

    如 cmets 中所述,您可以简单地使用 std::max,它采用初始化列表。

    一个示例调用是:

    auto maxNum = std::max({a, b, c});
    

    【讨论】:

    • 抱歉,这不符合规定的标准(提供预期的功能
    • @Walter “这不符合规定的标准”以什么方式?
    • 根据en.cppreference.com/w/cpp/algorithm/max 它声明T must meet the requirements of CopyConstructible in order to use overloads (3,4). 我猜这是不使用初始化列表重载的原因......因此沃尔特关于不可复制对象的评论;)
    • @AsteroidsWithWings 有两种方式:(1)我必须在我的项目中到处更改max(a,b,c)——目前这是通过重载实现的,而不是可变参数模板。 (2) 对于不可复制的对象,它会失败,并且会创建不需要的大对象副本。
    • @Walter 您的问题中没有说明这些标准。
    【解决方案4】:

    我建议 yao99 的答案应该是公认的答案。出于好奇,这里我向您介绍一个通过您自己的命名空间提供适配器的解决方案。这只会使用std::max 的二进制参数重载,因此不可能调用初始化列表重载。客户端代码仍然可以使用max,如下所示:

    适配器:

    #include <iostream>
    #include <algorithm>
    
    namespace variadicMax
    {
        // the variadic "max" recurses and reduces to a binary parameter version that we must implement
        template<typename T>
        constexpr inline T const& max(T const&x, T const&y)
        {
            return (std::max(x, y));
        }
    
        // the variadic overload recurses itself, removing two parameters (and adding one) each time.
        // Eventually it reduces to (x,y) which is handled by the other overload.
        template<typename T, typename...Args>
        constexpr inline T const& max(T const&x, T const&y, Args&&...z)
        {
            return (max (std::max(x, y), std::forward<Args>(z)...));
        }
    };
    

    客户:

    // this is the only change needed in clients:
    using variadicMax::max;
    
    int main()
    {
        double x, y, z, w, v;
    
        x = 1;  y = 2;  z = 3;  w = 4;  v = 5;
        auto m5 = max(x, y, z, w, v);  std::cout << m5 << std::endl;
        auto m5A = max(x, y, z, 4.0, v);  std::cout << m5A << std::endl;
    
        x = 1;  y = 2;  z = 3;
        auto m = max(x, y, z);  std::cout << m << std::endl;
    
        x = 2;  y = 3;  z = 1;
        auto m2 = max(x, y, z);  std::cout << m2 << std::endl;
    
        x = 3;  y = 2;  z = 1;
        auto m3 = max(x, y, z);  std::cout << m3 << std::endl;
    
        x = 3;  y = 2;
        auto m4 = max(x, y);  std::cout << m4 << std::endl;
    
        x = 3;  y = 2;
        auto m6 = max(3, 2);  std::cout << m6 << std::endl;
    
        x = 3;  y = 2;
        auto m7 = max(x, 2.0);  std::cout << m7 << std::endl;
    
        etc...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-05
      • 1970-01-01
      • 1970-01-01
      • 2015-09-11
      • 1970-01-01
      • 2014-01-14
      • 1970-01-01
      相关资源
      最近更新 更多