可变参数概念约束

Bon*_*ero 2 c++ c++-concepts c++20

不幸的是这段代码不起作用:

#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>

template<typename FirstArg, typename ... Args>
    requires (sizeof ... (Args) == 0 || (std::is_convertible_v<Args ..., FirstArg>))
constexpr void multi_max( FirstArg firstArg, Args const &... args )
{
    using namespace std;
    FirstArg &max = firstArg;
    auto findMax = [&]<size_t ... Is>( index_sequence<Is ...> iseq, tuple<Args ...> tArgs )
    {
        ((max = get<Is>( tArgs ) > max ? get<Is>( tArgs ) : max), ...);
    };
    findMax( make_index_sequence<sizeof ... (Args)>(), make_tuple( args ... ) );
}

int main()
{
    multi_max( 1 );
    //multi_max( 1, 2, 3 );
}
Run Code Online (Sandbox Code Playgroud)

注释部分不满足要求约束的右半部分。为什么 ?如果我删除第一个约束,编译器会抱怨将参数错误地解包到元组中。

chr*_*ris 6

查看编译器错误的相关部分:

注意:因为替换的约束表达式格式错误:变量模板“is_convertible_v”的模板参数太多

你正在使用is_convertible_v<int, int, int>. 您想要的是各个参数的所有测试都为 true,您可以使用折叠表达式来完成此操作:

requires (sizeof ... (Args) == 0 || (std::is_convertible_v<Args, FirstArg> && ...))
Run Code Online (Sandbox Code Playgroud)

然而,对于 0 个元素的包,折叠表达式将生成truefor &&,因此第一部分现在是多余的:

requires (std::is_convertible_v<Args, FirstArg> && ...)
Run Code Online (Sandbox Code Playgroud)

清理以使用该概念convertible_to而不是旧的类型特征:

requires (std::convertible_to<Args, FirstArg> && ...)
Run Code Online (Sandbox Code Playgroud)

现在事情看起来有点令人怀疑的方便。我们实际上可以将其移至模板参数并完全摆脱requires:

template<typename FirstArg, std::convertible_to<FirstArg> ... Args>
Run Code Online (Sandbox Code Playgroud)

该占位符将FirstArg作为第二个参数插入,并将给定类型作为第一个参数,因此给定的类型T将测试std::convertible_to<T, FirstArg>。