Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以使用折叠表达式实现max(A,max(B,max(C,D))?_C++_Templates_Variadic Templates_C++17_Fold Expression - Fatal编程技术网

C++ 我可以使用折叠表达式实现max(A,max(B,max(C,D))?

C++ 我可以使用折叠表达式实现max(A,max(B,max(C,D))?,c++,templates,variadic-templates,c++17,fold-expression,C++,Templates,Variadic Templates,C++17,Fold Expression,在尝试使用C++17折叠表达式时,我尝试实现maxsizeof,其中结果是最大的sizeof类型。 我有一个丑陋的折叠版本,它使用变量和lambda,但是我想不出一种方法来使用折叠表达式和std::max()来获得相同的结果 这是我的折叠版本: template<typename... T> constexpr size_t max_sizeof(){ size_t max=0; auto update_max = [&max](const size_t&am

在尝试使用C++17折叠表达式时,我尝试实现max
sizeof
,其中结果是最大的
sizeof
类型。 我有一个丑陋的折叠版本,它使用变量和lambda,但是我想不出一种方法来使用折叠表达式和
std::max()
来获得相同的结果

这是我的折叠版本:

template<typename... T>
constexpr size_t max_sizeof(){
    size_t max=0;
    auto update_max = [&max](const size_t& size) {if (max<size) max=size; };
    (update_max(sizeof (T)), ...);
    return max;
}


static_assert(max_sizeof<int, char, double, short>() == 8);
static_assert(max_sizeof<char, float>() == sizeof(float));
static_assert(max_sizeof<int, char>() == 4);

可以这样做吗?

只需使用c++17倍的表达式即可

template <typename ... Ts>
constexpr std::size_t max_sizeof ()
 {
   std::size_t  ret { 0 };

   return ( (ret = (sizeof(Ts) > ret ? sizeof(Ts) : ret)), ... ); 
 }

与您的原始版本没有什么不同。

可能不是您想要听到的,但不是。使用折叠表达式不可能做到这一点(纯1)。他们的语法根本不允许这样做:

折叠表达式将模板参数包折叠到 二进制运算符

折叠表达式:
(强制转换表达式折叠运算符…)
(…折叠运算符强制转换表达式)
(强制转换表达式折叠运算符…折叠运算符强制转换表达式)
折叠运算符:其中一个
+   -   *   /   %   ^   &   |   > 
+=  -=  *=  /=  %=  ^=  &=  |=  =  =
==  !=  <   >   =  &&  ||  ,    .*   ->*
因为函数调用表达式不是纯语法意义上的二进制运算符


1参考其他精彩答案。

如果您想在这里使用折叠表达式,那么您需要以某种方式使用操作符来调用
std::max
,而不是函数调用。下面是一个滥用
操作员^
的例子:

namespace detail {
    template<typename T, std::size_t N = sizeof(T)>
    struct type_size : std::integral_constant<std::size_t, N> { };

    template<typename T, auto M, typename U, auto N>
    constexpr auto operator ^(type_size<T, M>, type_size<U, N>) noexcept {
        return type_size<void, std::max(M, N)>{};
    }
}

template<typename... T>
constexpr std::size_t max_sizeof() noexcept {
    using detail::type_size;
    return (type_size<T>{} ^ ... ^ type_size<void, 0>{});
    // or, if you don't care to support empty packs
    // return (type_size<T>{} ^ ...);
}

从外部看,这两种实现是等效的;就实施而言,我个人更喜欢前者,但YMMV.:-]

我想使用折叠表达式和
std::max
编写等效函数。例如,对于3个元素,它应该扩展到

返回std::max(sizeof(A)、std::max(sizeof(B)、sizeof(C))

另一种可能的解决方案(基于fold表达式的递归,not)如下

template <typename T0>
constexpr std::size_t max_sizeof ()
 { return sizeof(T0); }
    
template <typename T0, typename T1, typename ... Ts>
constexpr std::size_t max_sizeof ()
 { return std::max(sizeof(T0), max_sizeof<T1, Ts...>()); }
模板
constexpr std::size\u t max\u sizeof()
{返回sizeof(T0);}
模板
constexpr std::size\u t max\u sizeof()
{return std::max(sizeof(T0),max_sizeof());}

不是折叠表达式,而是c++17提供的另一种方式-
if constexpr

template<class X, class Y, class...Ts>
constexpr std::size_t max_sizeof()
{
    auto base = std::max(sizeof(X), sizeof(Y));

    if constexpr (sizeof...(Ts) == 0)
    {
        // nothing
    }
    else if constexpr (sizeof...(Ts) == 1)
    {
        base = std::max(base, sizeof(Ts)...);
    }
    else
    {
        base = std::max(base, max_sizeof<Ts...>());
    }
    return base;
}
模板
constexpr std::size\u t max\u sizeof()
{
自动基准=标准::最大值(sizeof(X),sizeof(Y));
如果constexpr(sizeof…(Ts)==0)
{
//没什么
}
如果constexpr(sizeof…(Ts)==1)
{
基准=标准::最大值(基准,尺寸);
}
其他的
{
base=std::max(base,max_sizeof());
}
返回基地;
}

由于目前还没有人将此作为答案发布,因此最简单的方法就是使用为该问题准备的重载:使用
初始值设定项列表的重载:

template<typename... T>
constexpr size_t max_sizeof() {
    return std::max({sizeof(T)...});
}
模板
constexpr size\u t max\u sizeof(){
返回std::max({sizeof(T)…..});
}

只是为了好玩,这是ildjarn卓越解决方案主题的变体

namespace detail
 {
   template <std::size_t N>
   struct tSizeH : std::integral_constant<std::size_t, N> { };

   template <std::size_t M, std::size_t N>
   constexpr tSizeH<std::max(M, N)> operator^ (tSizeH<M>, tSizeH<N>);
 }

template <typename ... T>
constexpr std::size_t max_sizeof() noexcept
 { return decltype((detail::tSizeH<sizeof(T)>{} ^ ...))::value; }
名称空间详细信息
{
模板
struct tSizeH:std::integral_常量{};
模板
constexpr tSizeH操作员^(tSizeH,tSizeH);
}
模板
constexpr std::size\t max\u sizeof()无例外
{返回decltype((detail::tSizeH{}^…)::value;}
有点简化,因为(A)helper类只使用类型的
sizeof()
(直接在
max_sizeof()
中解析),(b)不使用基于
void
和零的终值,(c)声明了
运算符^()
,但未实现(不需要实现它:仅对返回类型感兴趣)和(d)
max_sizeof()
使用
decltype()
而不是调用
operator^()
(因此不需要实现它)。

当然,没有问题

template<class Lhs, class F>
struct foldable_binop_t {
  Lhs lhs;
  F f;
  template<class Rhs>
  auto operator*(Rhs&& rhs) &&
  -> foldable_binop_t< std::result_of_t<F&(Lhs&&, Rhs&&)>, F >
  {
    return { f(std::forward<Lhs>(lhs), std::forward<Rhs>(rhs)), std::forward<F>(f) };
  }
  Lhs operator()() && { return std::forward<Lhs>(lhs); }
  operator Lhs() && { return std::move(*this)(); }
  Lhs get() && { return std::move(*this); }
};
template<class F>
struct foldable_t {
  F f;
  template<class Lhs>
  friend foldable_binop_t<Lhs, F> operator*( Lhs&& lhs, foldable_t&& self ) {
    return {std::forward<Lhs>(lhs), std::forward<F>(self.f)};
  }
  template<class Rhs>
  foldable_binop_t<Rhs, F> operator*( Rhs&& rhs ) && {
    return {std::forward<Rhs>(rhs), std::forward<F>(f)};
  }
};
template<class F>
foldable_t<F> foldable(F f) { return {std::move(f)}; }
整天写东西很烦人,所以

#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
成功了

template<class...Xs>
auto result3( Xs... xs ) {
  return (foldable(OVERLOADS_OF((std::max))) * ... * xs).get();
}
模板
自动结果3(Xs…Xs){
return(可折叠(重载((std::max))*…*xs.get();
}
甚至

template<class...Xs>
constexpr auto result4( Xs... xs )
  RETURNS( (foldable(OVERLOADS_OF((std::max))) * ... * xs).get() )
模板
constexpr自动结果4(Xs…Xs)
返回((可折叠(重载((std::max))*…*xs.get())
哪个更具表现力,并且没有异常/constexpr,等等。

这个怎么样(由提供):

模板
constexpr auto max(const U&U,const V&…V)->typename std::common_type::type{
使用rettype=typename std::common_type::type;
rettype结果=静态施法(u);
(void)std::初始值设定项_list{((v>result)?(result=static_cast(v),0):0);
返回结果;
}

在c++14中工作,因此它不使用c++17折叠表达式,但它的工作方式如下所示:

max(std::initializer_list)
存在。是否有理由使用折叠,而不仅仅是
模板constexpr size_t max_sizeof(){return std::max({sizeof(t)}}
@DaveS为什么不工作?@schorsch312:那么它就不能是
constepr
模板constepr std::size\t max\u sizeof=sizeof(std::aligned\u union\t)
这不容易阅读…没有办法将其重写为折叠递归形式吗?我对技术上的正确性投了赞成票,但我希望有人能想出更好的解决方案,因为像YSC一样,我在解析这一问题时遇到了困难。我的意思是,我可以猜出它现在的作用,因为我问了这个问题,但如果这段代码来给我审阅,我会的糊涂了。:@YSC-嗯。。。不是很聪明,但是(iMHO)对于一个熟练的C++程序员来说应该是容易阅读的;无论如何,我添加了一个版本,它使用了
std::max()
,应该更简单;但是“fold recursive form”@nosensetal是什么意思?不幸的是,新的c++17 fold表达式可以与运算符一起工作;我所能想到的最好的方法是使用逗号作为运算符,在每个
sizeof()
上迭代某些内容;“某物”可以是基于te的赋值
template<class...Xs>
auto result( Xs... xs ) {
  auto maxer = [](auto&&...args){return (std::max)(decltype(args)(args)...);};
  return ((0 * foldable(maxer)) * ... * xs).get();
}
template<class...Xs>
auto result2( Xs... xs ) {
  auto maxer = [](auto&&...args){return (std::max)(decltype(args)(args)...);};
  return (foldable(maxer) * ... * xs).get();
}

int main() {
  int x = result2( 0, 7, 10, 11, -3 ); // or result
  std::cout << x << "\n";
}
  auto maxer = [](auto&&...args){return (std::max)(decltype(args)(args)...);};
#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
template<class...Xs>
auto result3( Xs... xs ) {
  return (foldable(OVERLOADS_OF((std::max))) * ... * xs).get();
}
template<class...Xs>
constexpr auto result4( Xs... xs )
  RETURNS( (foldable(OVERLOADS_OF((std::max))) * ... * xs).get() )
template<typename U, typename ... V>
constexpr auto max(const U &u, const V &... v) -> typename std::common_type<U, V...>::type {
  using rettype = typename std::common_type<U, V...>::type;
  rettype result = static_cast<rettype>(u);
  (void)std::initializer_list<int>{ ( (v > result)?(result = static_cast<rettype>(v), 0):0 )... };
  return result;
}