大括号初始化函数参数中的元组



有问题的主要问题是,我想编写一个函数,该函数需要两组可变长度的参数。

我决定采用的抽象是模拟以下调用语法:

f({a,b,c},x,y);

如果abc都具有相同的类型,则可以使其与一起工作

template <typename X, typename... A>
void f(std::initializer_list<X> xs, A&&... as) { . . . }

但是使用std::tuple而不是std::initializer_list的类似函数定义不允许使用我想要的语法。

template <typename... X, typename... A>
void f(const std::tuple<X...>& xs, A&&... as) { . . . }

有什么技巧可以让第一组中的类型是异构的吗?

附录:一般来说,我不知道X...的大小。

附录2:有人知道支撑初始值设定项适用于std::tuple t{a,b,c},但不适用于模板参数上下文的技术原因吗?是因为在我的例子中xs没有被X...扩展吗?

不,目前使用您想要的语法是不可能的。初始值设定项列表只能推导为数组或std::initializer_list,这两种类型都是同构类型。

这是一条特殊的规则。初始值设定项列表没有类型,因此无法推导为其他类型。如果函数参数不是数组或std::initializer_list,则为其提供初始值设定项列表的参数将成为非推导上下文,模板参数推导将忽略它。

特别是类模板参数推导不能在函数参数中完成,以从支持的初始值设定项列表中确定类型,因为它可以在C++17以来的变量定义中完成。这样的功能没有添加到语言中。

原则上,通过使用例如std::variant的数组作为参数,可以允许有限数量的不同类型,但这只会在运行时解析为类型,不太可能是您想要的。

您需要将类型名称或函数调用添加到初始值设定项列表大括号中,如中所示

f(std::forward_as_tuple(a, b, c), x, y)

或者您可以使用标记类型来指示平面参数列表中第一个包的结束:

f(a, b, c, tag, x, y)

然后可以通过一些模板工作来检测标签。

您想要的目前并不方便,但还有另一种替代方案:

f(a, b, c)(x)(y)();

如果您利用f不返回任何内容这一事实,您可以返回一个lambda或其他接受进一步参数的函数对象。一个空的参数列表可能意味着,将不会有进一步的参数。

示例:

template <typename ...A>
auto f(A&& ...a)
{
if constexpr (sizeof...(a) > 1)
{
std::tuple(std::forward<A>(a)...);
}
else
{
// burp
}
return [](auto&& ...a)
{
if constexpr (sizeof...(a))
{
return f(std::forward<decltype(a)>(a)...);
}
else
{
std::cout << "done" << std::endl;
}
};
}
int main()
{
f(1, 2, 3)(4)(5)();
return 0;
}

https://wandbox.org/permlink/eAB2S4aCxxiSlMAF

编辑:也试试这个替代方案:

template <typename ...A>
void f(std::any const(&)[3], A&&...)
{
}
int main()
{
f({1, 2u, '3'}, 4., 5.f);
return 0;
}

https://wandbox.org/permlink/0OhoJpQ1YpSGOV2c

您可以使用std::variant来实现类型安全或比STL提供的更快的功能。当然,您也可以编写自己的容器。

编辑2:然后再说一遍:

template <typename ...A>
void f(std::initializer_list<std::any>, A&&...)
{
}
int main()
{
f({1, 2u, '3'}, 4., 5.f);
return 0;
}

当然,不要使用std::any,而是使用你自己喜欢的类型。

https://wandbox.org/permlink/rqSVK6aj5zuSFRcf

编辑3:还有另一种方法:

class U
{
void const* const v_;
using typeid_t = void(*)();
typeid_t const tid_;
public:
template <typename T>
static typeid_t type_id() noexcept
{
return typeid_t(U::type_id<T>);
}
template <typename A>
U(A&& a) noexcept: v_(&a), tid_(type_id<std::remove_cvref_t<A>>()) {}
template <typename A>
A const& get() const noexcept { return *static_cast<A const*>(v_); }
auto type_id() const noexcept { return tid_; }
};
template <typename... A>
void f(U const (&a)[3], A&&...)
{
std::cout << a[0].get<double>() << std::endl;
}
int main()
{
f({1.5, 2, 3.f}, 'a', 1);
return 0;
}

您可以将typeid检查设置为可选,并仅在调试构建中编译它。

https://wandbox.org/permlink/wgXOycB5I3bb3ExV

相关内容

  • 没有找到相关文章

最新更新