在 C++20 中实现可变参数 Max 函数

MyC*_*ass 9 c++ templates function-templates variadic-templates c++20

尽管如此,事实上,我们有std::max,我想尝试是否可以制作一个Max采用可变参数并递归调用Max 以查找最大元素的版本。

我在堆栈溢出中看到了类似的帖子,但这些帖子已经很旧了,而且大多数都std::max在内部使用。由于我有一个特定的错误并使用较新的编译器,因此这篇文章不容易重复。

以下是我写的代码:

#include <iostream>
#include <string>
#include <format>
using namespace std::string_literals;

template <typename T>
constexpr T Max(T&& value)
{  
  return value;
}

template <typename T, typename... Ts>
constexpr T Max(T&& value, Ts&&... args)
{
    const T maxRest = Max(args...);

    return (value > maxRest) ? value : maxRest;
}

int main()
{
    std::cout << std::format("Maximum integer: {}\n", Max(1));
    std::cout << std::format("Maximum integer: {}\n", Max(5, 2, 10, 6, 8));
    std::cout << std::format("Maximum integer: {}\n", Max("string1", "string2"s));  // error in this line!!
    std::cout << std::format("Maximum double: {}\n", Max(3.14, 1.23, 2.56, 0.98));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为此我得到:

main.cc(79, 21) : error C2440 : 'initializing' : cannot convert from 'std::string' to 'const char (&)[8]'
main.cc(79, 21) : message: Reason: cannot convert from 'std::string' to 'const char [8]'
main.cc(79, 21) : message: No user - defined - conversion operator available that can perform this conversion, or the operator cannot be called
main.cc(87, 55) : message: see reference to function template instantiation 'T Max<const char(&)[8],std::string>(T,std::string &&)' being compiled
with
[
    T = const char(&)[8]
]
Run Code Online (Sandbox Code Playgroud)
  • 我认为错误来自函数调用:Max("string1", "string2"s));。我不知道,如何解决这个问题。
  • 同样,我也觉得我正在编写更多内容来 在Max中实现此功能。有人建议将这两个功能合二为一吗?Max

JeJ*_*eJo 13

同样,我也觉得我正在编写更多内容来在Max [...] 中实现此功能?

您的Max函数可以通过以下方式最大限度地简化

constexpr auto Max(auto const& value, auto const&... args)
{
    if constexpr (sizeof...(args) == 0u) // Single argument case!
        return value;
    else // For the Ts...
    {
        const auto max = Max(args...);
        return value > max ? value : max;
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅 godbolt.org 中的现场演示

更新:正如@TedLyngmo在评论部分所指出的,如果您只传递连续的const char*s (字符串文字),则上述内容不起作用 。前任。设想

Max("string1"s, "string2", "string4", "string3") // result is "string2" instead of "string4"
Run Code Online (Sandbox Code Playgroud)

因为这会导致指针比较而不是您想要的比较。您原来显示的代码也是如此。您可能需要单独处理这种情况。

例如,在下面的代码示例中,如果value可以转换为std::string_view,我们将其转换为std::string_view并进行更大的检查:

#include <type_traits>  // std::is_convertible

constexpr auto Max(auto const& value, auto const&... args)
{
    if constexpr (sizeof...(args) == 0u) // Single argument case!
    {
        if constexpr (std::is_convertible_v<decltype(value), std::string_view>)
            return std::string_view{value};
        else
            return value;
    }
    else // For the Ts...
    {
        const auto max = Max(args...);
        return value > max ? value: max;
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅 godbolt.org 中的现场演示

同样,每次使用此Max函数时,请始终记住检查传递的参数是否是某种类型的指针,这显然不是由它处理的。


我认为错误来自函数调用:Max("string1", "string2"s)); 。我不知道,如何解决这个问题。

当您调用 时Max("string1", "string2"s)),编译器将T(即返回类型)推导为 , const char[8]即第一个参数(即 )的类型"string1"。然而,第二个参数是 a std::string(即"string2"s)。现在该行:

const T maxRest = Max(args...);
Run Code Online (Sandbox Code Playgroud)

thisstd::string现在必须可以隐式转换为 const char [8].This 不可行,因此编译器会产生类型不匹配错误。

要解决这个问题,您只需让编译器为您推断类型即可;这意味着,不要定义或假设返回类型始终为T,而是使用auto以便编译器可以为您推断出类型。

template <typename T, typename... Ts>
constexpr auto Max(T const& value, Ts const&... args)
//        ^~~~ ---> Simply 'auto'
{
    const auto maxRest = Max(args...);
    //    ^~~~ ---> Simply 'auto'
    return (value > maxRest) ? value : maxRest;
}
Run Code Online (Sandbox Code Playgroud)

请参阅 godbolt.org 中的现场演示

或者,您也可以使用std::common_type_t 来定义返回类型。

#include <type_traits> // std::common_type_t

        template <typename T, typename... Ts>
constexpr auto Max(T const& value, Ts const&... args)
-> std::common_type_t<T, Ts...>
{
    // ....
}
Run Code Online (Sandbox Code Playgroud)

  • @JeJo这是那些该死的指针:-)也许捕获`char*`并将它们变成`string_view`s将是一个选择 (4认同)
  • @TedLyngmo 感谢您提出这个问题。我忘记了即使 `std::max` 也有同样的问题:[为什么 std::max 不适用于字符串文字?](/sf/ask/4838958211/为字符串文字工作/69128027#69128027)。我已经更新了..:) (2认同)