带有初始化列表的约束自动 std::convertible_to

Constrainted auto std::convertible_to with initializer list

你好 Whosebug 的人,我最近正在尝试学习 c++20 constrainted auto 作为函数参数以减少样板代码。 我有一个 class 模板,它是某些数据类型的包装器,例如 std::int64_t, bool, double, std::string,将来可能会添加更多,它有一个接受数据类型的函数和一个接受数据类型的重载函数std::initializer_list<data_t> 用于数组操作。

template<typename data_t>
void set_data(data_t a_data)

template<typename data_t>
void set_data(std::initializer_list<data_t> a_dataList)

如果我直接调用这些 setter 函数,它们就可以正常工作。

在管理所有这些数据的 api class 中,我有一个公开的 api 做基本相同的事情,我有这个:

template<typename data_t>
void bind(Wrapper<data_t>& a_data, const std::convertible_to<data_t> auto a_value)
{
    a_data.set_data(a_value);
}

template<typename data_t>
void bind(Wrapper<data_t>& a_data, const std::initializer_list<data_t> a_valueList)
{
    a_data.set_data(a_value);
}

第一个函数按预期工作,例如,我可以将任何可转换数据类型传递给 std::int64_t 的包装器,但如果我想将 initializer_list 传递给后者,我必须像这样

显式地将类型转换为 data_t
Wrapper<std::int64_t> iA;

bind(iA, 100); // works
iA.set_data(100) // works

bind(iA, {1,2,3,4,5}); // no
iA.set_data({1,2,3,4,5}); // works
bind(iA, {(std::int64_t)1, (std::int64_t)2, (std::int64_t)3, (std::int64_t)4});
// works

所以我的问题终于出来了:如何用 std::initializer_list 实现 std::convertible_to 这样的东西,这样我就不必像上面那样输入强制转换了?或者这根本可行吗?

好的,在发布问题之前我应该​​做的一些挖掘之后,我找到了这个解决方案:

template <typename data_t>
void Bind(Wrapper<data_t>& a_data, const std::convertible_to<data_t> auto... a_valueList) noexcept
{
    a_data.set_data({static_cast<data_t>(a_valueList)...});
}

我要做的就是在适当的位置构造一个 std::initializer_list 所需的 data_t 类型,并在调用函数时跳过列表构造

bind(iA,1,2,3,4,5); // works, no need for brackets

您的问题是 C++ 正在使用第一个和第二个参数推导 data_t。如果他们不同意,则没有 cookie。

template<typename data_t>
void bind(Wrapper<data_t>& a_data, std::type_identity_t<std::initializer_list<data_t>> a_valueList)

这会阻止第二个参数的推导。