尽管事实上,我们有
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;
}
为此我得到:
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]
]
Max("string1", "string2"s));
。我不知道,如何解决这个问题。Max
c++20 中的函数。有人有什么建议吗
将两个 Max
函数合二为一?同样,我也感觉我正在编写更多内容来实现
c++20中的这个Max
功能[...]?
您的
Max
功能可以通过最大限度地简化
if constexpr
(自 c++17 起)。
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;
}
}
更新:正如@TedLyngmo在评论部分指出的那样,如果您只传递连续的
const char*
(字符串文字),则上述方法不起作用。前任。场景
Max("string1"s, "string2", "string4", "string3") // result is "string2" instead of "string4"
因为这会导致指针比较而不是您想要的比较。您原来显示的代码也是如此。您可能需要单独处理这种情况。
例如,在下面的代码示例中,如果
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;
}
}
同样,每次使用这个
Max
函数时,始终记得检查传递的参数是否是某种类型的指针,这显然不是由它处理的。
我认为错误来自函数调用:
。 我不知道如何解决这个问题。Max("string1", "string2"s));
当您调用
Max("string1", "string2"s))
时,编译器会推导 T
(即返回类型)为
const char[8]
,这是第一个参数的类型(即"string1"
)。然而,第二个参数是 std::string
(即 "string2"s
)。现在该行:
const T maxRest = Max(args...);
这个
std::string
现在必须可以隐式转换为 const char [8]
。这是不可行的,因此编译器会产生类型不匹配错误。
要解决这个问题,您只需让编译器为您推断类型即可;这意味着,而不是定义或假设 返回类型将始终为
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;
}
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...>
{
// ....
}
同样,我也感觉我正在编写更多内容来实现
c++20中的这个Max
功能[...]?
作为其他答案的扩展,使用折叠表达式,
Max
也可以成为非递归的。
#include <type_traits> // std::common_type, std::remove_cvref
#include <functional> // std::greater
template<typename... T> // common type helper
using CommonType = std::common_type_t<std::remove_cvref_t<T>...>;
constexpr auto Max(auto const& value, auto const&... args)
{
CommonType<decltype(value), decltype(args)...> maxVal = value;
return sizeof...(args) == 0u ? maxVal
: (((maxVal = std::greater{}(args, maxVal) ? args : maxVal), ...)
, maxVal);
}
但是,对于连续字符串文字的情况,需要添加一些内容:
template<typename... T> // common type helper
using CommonType = std::common_type_t<std::remove_cvref_t<T>...>;
// For string literals comparison.
constexpr auto handleStrLiterals(auto const& t)
{
if constexpr (std::is_convertible_v<decltype(t), std::string_view>)
return std::string_view{ t };
else return t;
};
constexpr auto Max(auto const& value, auto const&... args)
{
CommonType<decltype(handleStrLiterals(value)), decltype(args)...>
maxVal = handleStrLiterals(value);
return sizeof...(args) == 0u ? maxVal
: (((maxVal = std::greater{}(args, maxVal) ? args : maxVal), ...)
, maxVal);
}