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

NoS*_*tAl 24 c++ templates variadic-templates fold-expression c++17

在尝试使用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);
Run Code Online (Sandbox Code Playgroud)

我想用折叠表达式编写等效函数std::max().例如,对于3个元素,它应该扩展为

return std::max(sizeof (A), std::max(sizeof(B), sizeof (C)));
Run Code Online (Sandbox Code Playgroud)

有可能吗?

Sto*_*ica 24

可能不是你想听到的,但没有.使用折叠表达式不可能(纯粹为1).他们的语法根本不允许它:

[expr.prim.fold]

折叠表达式在二元运算符上执行模板参数包的折叠 .

fold-expression:
  ( cast-expression fold-operator ... )
  ( ... fold-operator cast-expression )
  ( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator: one of
  + ??- ??* ??/ ??% ??^ ??& ??| ??<< ??>> 
  +=??-=??*=??/=??%=??^=??&=??|=??<<=??>>=??=
  ==??!=??< ??> ??<=??>=??&&??||??,  ??.* ??->*
Run Code Online (Sandbox Code Playgroud)

仅仅因为函数调用表达式不是纯语法意义上的二元运算符.


1请参阅其他精湛的答案.

  • 因此,如果OP可以定义一个二进制运算符(比如`运算符,`)来处理包装的`size_t`,它们可以使用fold表达式吗? (2认同)

ild*_*arn 18

如果你想在这里使用fold表达式,那么你需要以某种方式使用运算符来调用std::max而不是函数调用.这是滥用operator^这个目的的一个例子:

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>{} ^ ...);
}
Run Code Online (Sandbox Code Playgroud)

Online Demo


编辑:@除去巴里的建议,Ttype_size(改名为max_val这里):

namespace detail {
    template<auto N>
    struct max_val : std::integral_constant<decltype(N), N> { };

    template<auto M, auto N, auto R = std::max(M, N)>
    constexpr max_val<R> operator ^(max_val<M>, max_val<N>) noexcept {
        return {};
    }
}

template<typename... T>
constexpr std::size_t max_sizeof() noexcept {
    using detail::max_val;
    return (max_val<sizeof(T)>{} ^ ... ^ max_val<std::size_t{}>{});
    // or, if you don't care to support empty packs
    // return (max_val<sizeof(T)>{} ^ ...);
}
Run Code Online (Sandbox Code Playgroud)

Online Demo

在外部,两种实现都是等效的; 在实施方面,我个人更喜欢前者,但YMMV.: - ]

  • @NoSenseEtAl:C++/CLI有`^`来指定句柄,它们是指针的托管等价物,但它不是运算符(C++/CLI确实添加了一个运算符,`operator%`,相当于本机一元`运算符*`).`^`是一个二进制运算符,默认情况下按位XOR. (3认同)
  • 可以使用`template <size_t N> struct type_size:integral_constant <size_t,N> {}`并避免使用`void`. (2认同)

Bar*_*rry 18

既然没有人发布这个作为答案,那么用最小的努力做到这一点的最简单方法就是使用std::max()现成的重载来解决这个问题:一个需要initializer_list:

template<typename... T>
constexpr size_t max_sizeof() {
    return std::max({sizeof(T)...});
}
Run Code Online (Sandbox Code Playgroud)


max*_*x66 7

只是玩c ++ 17倍表达式

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

   return ( (ret = (sizeof(Ts) > ret ? sizeof(Ts) : ret)), ... ); 
 }
Run Code Online (Sandbox Code Playgroud)

或者,使用的事实std::max()constexpr从C++ 14开始(因此它是在C++ 17)

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

   return ( (ret = std::max(sizeof(Ts), ret)), ... ); 
 }
Run Code Online (Sandbox Code Playgroud)

与您的原始版本没有太大区别.

  • @NoSenseEtAl - 遗憾的是,新的c ++ 17折叠表达式适用于运算符; 我能想象的最好的是使用逗号作为运算符来迭代每个`sizeof()`; "某事"可以是基于三元运算符或`std :: max()`或其他的赋值,但我认为不可能做得更好. (3认同)
  • @NoSenseEtAl - 无论如何,看看ildjarn的精彩答案:他重新定义一个运营商以获得你想要的东西. (3认同)