在C++ 11中使用max <int>作为谓词

use*_*979 23 c++ c++11 c++14

在C++ 03中,以下代码可以正常工作:

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    std::vector<int> v2;
    v2.push_back(2);
    v2.push_back(3);
    v2.push_back(4);

    std::transform(v.begin(), v.end(), v2.begin(), v2.begin(), std::max<int>);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在C++ 11中,这不起作用,因为它为std::max包含的内容添加了一个重载initializer_list.因此,您必须使用非常难看的强制转换来选择正确的重载:

static_cast<const int& (*)(const int&, const int&)>(std::max)
Run Code Online (Sandbox Code Playgroud)

我有几个问题.

  • 为什么标准委员会决定这样做,知道它会(可能)破坏现有代码并迫使用户创建一个丑陋的演员?
  • 未来的C++标准是否会试图缓解这个问题?
  • 什么是变通方法?

T.C*_*.C. 11

如果您经常这样做,您可能想要编写一个透明的函子包装器:

struct my_max {
    template<class T>
    const T& operator()(const T& a, const T& b) const{
        return std::max(a, b);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后你就可以做到

std::transform(v.begin(), v.end(), v2.begin(), v2.begin(), my_max());
Run Code Online (Sandbox Code Playgroud)

无论什么时候你需要它,而不是每次都写一个lambda或演员.这与透明运算符仿函数基本相同 - 让模板参数在实际调用站点推断,而不是在创建仿函数时明确指定.

如果你想让这个更加漂亮,你甚至可以operator()采用异构类型并添加完美的转发和使用尾随返回类型:

struct my_max {
    template<class T, class U>
    constexpr auto operator()( T&& t, U&& u ) const
      -> decltype(t < u ? std::forward<U>(u) : std::forward<T>(t)){
        return t < u ? std::forward<U>(u) : std::forward<T>(t);
    }
};
Run Code Online (Sandbox Code Playgroud)

在C++ 14中,这简化为

struct my_max {
    template<class T, class U>
    constexpr decltype(auto) operator()( T&& t, U&& u ) const{
        return t < u ? std::forward<U>(u) : std::forward<T>(t);
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 请注意,当"T"或"U"是具有"窃取"移动ctor的类型时,转发版本将在(有点病态)情况下可怕地破坏,要么"t"或"u"是r值参考, `<`按值取适当的操作数. (2认同)