【问题标题】:C++ Variadic functions with no argumentC ++ Variadic函数没有参数
【发布时间】:2019-10-20 09:46:03
【问题描述】:

我有多个课程(为简单起见,此处为FooBar

struct Bar {};
struct Foo {};

以及一个接受单个模板参数并根据该类型执行某些操作的函数:

template <typename T>
constexpr void doSomething() { cout << "Am I a Foo? " << is_same<T,Foo>::value << endl; }

在我的代码中,我得到了Foos 和Bars 的模板参数包,我应该对它们中的每一个都调用doSomething() 函数(我不关心其中的顺序)执行哪些函数)。

doStuff<Foo, Bar, Bar>(); // --> True / False / False

到目前为止,我能想到的唯一解决方案是:

template <typename... Ts>
class Doer;

template <>
struct Doer <> {
    static constexpr void doStuff() {}
};

template <typename Head, typename... Tail>
struct Doer <Head, Tail...> {
    static constexpr void doStuff() {
        doSomething<Head>();
        Doer<Tail...>::doStuff();
    }
};

template <typename... Ts>
constexpr void doStuff() {
    return Doer<Ts...>::doStuff();
}

doStuff<Foo, Bar, Bar>(); // --> True / False / False

它有效,但我觉得它相当混乱。我不得不使用带有部分特化的类模板,因为函数模板只支持完全特化。我也试过了

constexpr void doStuff() { }

template <typename Head, typename... Tail>
constexpr void doStuff() {
    doSomething<Head>();
    doStuff<Tail...>();   // --> Compile Error
}

但编译器失败了,因为它无法确定doStuff&lt;&gt;() 实际上是doStuff()。如果我的可变参数函数中有参数,那么编译器足够聪明地解决这个冲突,因为它应用了模板类型推导:

constexpr void doStuff() { }

template <typename Head, typename... Tail>
constexpr void doStuff(Head arg, Tail... args) {
    doSomething<Head>();
    doStuff(args...);
}

Foo f1;
Bar b1, b2;
doStuff<Foo, Bar, Bar>(f1, b1, b2); // --> True / False / False

我错过了什么吗?有没有办法让我的可变参数函数在不使用函数参数或类模板的情况下工作?

【问题讨论】:

标签: c++ variadic-templates variadic-functions template-meta-programming function-templates


【解决方案1】:

但是编译器失败了,因为它无法确定 doStuff() 实际上是 doStuff()。

怎么样

template <int = 0>
constexpr void doStuff() { }

template <typename Head, typename... Tail>
constexpr void doStuff() {
    doSomething<Head>();
    doStuff<Tail...>();
}

?

我的意思是:如果问题是,最后,模板可变参数列表为空,则使用模板参数(完全不同:整数而不是类型)和默认值转换模板版本中的基本情况。

所以,当Tail... 为空时,调用doStuff&lt;Tail...&gt;(),即doStuff&lt;&gt;(),匹配doStuff&lt;0&gt;()(考虑第一个函数中的默认值)所以调用ground case。

无论如何:如果你可以使用 C++17,你可以避免递归,并且使用逗号运算符的强大功能和模板折叠,你可以简单地编写

template <typename... Ts>
constexpr void doStuff() {
    (doSomething<Ts>(), ...);
}

在 C++14 中,您可以按如下方式模拟模板折叠

template <typename... Ts>
constexpr void doStuff() {
    using unused = int[];

    (void) unused { 0, ((void)doSomething<Ts>(), 0)... };
}

上述解决方案也适用于 C++11,但不适用于 constexpr(但在 C++11 中 doSomething() 也不能是 constexpr)。

考虑到您不关心函数的执行顺序,我提出了一个维护constexpr 的 C++11 解决方案,它基于假函数调用中的模板包扩展(或也许不是假的……见)。

但这要求doSomething()constexpr(因此,在C++11 中,不能是void)而且doStuff() 也不能是void

#include <iostream>

template <typename T> 
constexpr std::size_t doSomething ()
 { return sizeof(T); }

template <typename ... Ts>
constexpr int fakeFunc (Ts const & ...)
 { return 0; }

template <typename ... Ts>
constexpr int doStuff ()
 { return fakeFunc( doSomething<Ts>()... ); }


int main()
 {
   constexpr int a { doStuff<char, short, int, long, long long>() };

   (void)a;
 }

【讨论】:

    猜你喜欢
    • 2016-06-30
    • 2020-11-11
    • 2015-12-27
    • 1970-01-01
    • 2016-09-11
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    相关资源
    最近更新 更多