【问题标题】:function with nested variadic template具有嵌套可变参数模板的函数
【发布时间】:2021-02-10 20:59:48
【问题描述】:

您能否使用可变参数模板编写一个函数,该模板接受任意元组列表,每个元组都有一组不同的参数?所以你会有类似的东西:

template< /* some crazy variadic thing...*/ >
void func( ... ) {}

func(make_tuple(1,2), make_tuple("hello"));

SFINAE 来救援! 进一步了解杰弗里的回答,我写了这个小sn-p。您可以将元组以外的类型放在 func 的参数列表中的任何位置,它将编译并运行,当它遇到不是模板类的第一个类型时,它只会中断我的打印链。 seqgens 来自 here

template<typename T>
int print(T& t) {
        cout << t << " ";
        return 0;
}

template<typename... T> void dumby(T...) {}

// so other template classes don't cause error (see bar below)
template<typename... A>
void expand(A... a) {}

template<typename... A, int... S>
void expand(tuple<A...> a, seq<S...>) {
        dumby(print(get<S>(a))...);
        cout << endl;
}

template<class... Types>
void func(Types...) {}

template<template<typename...> class A, class... Types, class... tup_types>
void func(A<tup_types...> a, Types... args) {
        expand(a, typename gens<sizeof...(tup_types)>::type());

        func(args...);
}

template<typename... A> struct bar {};

int main () {
        func(make_tuple(0,1), make_tuple(2), 1, make_tuple("hello"), 0);
        func(make_tuple(0,1), bar<int,int>(), make_tuple(2), 1, make_tuple("hello"), 0);
}

我必须找到一个实际的用例来进行尝试,但我认为这是暂时的成功!

【问题讨论】:

  • 用例是什么?你会怎么写正文?
  • 嗯,它是 C++;所以显而易见的答案是肯定的:P 但我相信有人会愿意详细说明。
  • @CoffeeandCode,实际上是不可能的。
  • @Jefffrey 在我的代码中,我有一个工厂,我可以在其中调用具有任意参数的构造函数,然后调用具有任意参数的初始化器成员。我可以这样做,因为函数的数量是有限的。但这让我对一般情况感到好奇。

标签: c++ templates variadic-templates


【解决方案1】:

是的,只需使用带有元组的基本函数,然后使用可变模板/参数创建一个同名的函数。

template<typename ... Types>
void func(const std::tuple<Types...> &Tuple){
    // work with tuple
}

template<typename TupleType, typename ... TupleTypes>
void func(const TupleType &arg, const TupleTypes &... args){
    func(arg);
    func(args...);
}

int main(){
    func(std::make_tuple(1, 2), std::make_tuple("hello"));
}

这将为您提供很大的灵活性,因为您可以知道 tuplethrowstatic_assert 或任何您喜欢的类型的数量,当您遇到不喜欢的东西时,或者您可以更进一步并在函数上使用 std::enable_if 以仅允许您的元组使用某些条件!

此函数仅适用于您所要求的std::tuple,但您可以通过将第一个函数更改为:

进一步扩展它以允许使用为其类型接受多个模板参数的任何容器:
template<typename ... Types, template<typename...> class TupleType>
void func(const TupleType<Types...> &Tuple){
    // Work with any type inter-face-able like a tuple
}

编辑

这可以用C++17 fold expressions 更简洁:

template<typename ... Ts>
void func(const std::tuple<Types...> &Tuple){
    // ...
}

template<typename ... Tuples>
void func(const Tuples &... tuples){
    (func(tuples), ...);
}

【讨论】:

    【解决方案2】:

    这是不可能的。可以强制参数的类型与static_assertstd::enable_if 相同,但std::tuple 的不幸现实是它是一个类模板,因此可以生成多种不同的类型。

    最好的方法是使用SFINAE。例如:

    template<class A>
    void func(A a) {
        std::cout << "First of last: " << std::get<0>(a) << '\n';
    }
    
    template<class A, class... Types>
    void func(A a, Types... args) {
        std::cout << "First of element: " << std::get<0>(a) << '\n';
        func(args...);
    }
    

    Live demo

    上面的例子will succeed当所有元素都是元组时,but fail当它们不是。

    【讨论】:

    • 为什么需要template &lt;class... Types&gt; void func(Types...)
    猜你喜欢
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    相关资源
    最近更新 更多