c++ 具有自定义结构类型的可变参数的函数

0pizxfdo  于 2023-02-01  发布在  其他
关注(0)|答案(3)|浏览(167)

我来自Swift背景,虽然我也懂一些C,但这是我第一次写C++代码。
在Swift中,可以编写一个接受任意数量参数的函数:

func foo(bar: String...) {
    // ...
}

并且bar可以是任何类型(字符串、布尔、结构、枚举等)。
我想知道在C++中是否也可以这样做。所以,理想情况下我会写:

struct X {
    string s;
    X(int);
    // ...
}

void foo(string s, ...) {
    // ...
}

foo("mystr", X(1), X(2), X(3));

foo中,我可以访问参数列表,有点类似于printf函数。
现在我使用vector<X>作为参数,因为所有的参数都是X类型。然而,在我看来,这使得调用foo有点难看:

foo("mystr", { X(1), X(2), X(3) });

由于我对C++知识的严重缺乏,我看不到任何解决方案吗?

**编辑:**这是我特别希望在foo中完成的工作:

string ssub(string s, vector<X> v) {
    int index, i = 0;

    while (1) {
        index = (int)s.find(SUB);
        if (index == string::npos) { break; }
        s.erase(index, string(SUB).size());
        s.insert(index, v[i].tostr());
        i++;
    }

    return s;
}

基本上,只要给我一种顺序访问参数的方法,一切都是好的。

rta7y2nd

rta7y2nd1#

这是众多方法中的一种。
您可以将整个程序复制/粘贴到IDE/编辑器中。

#include <utility>
#include <iostream>
#include <typeinfo>
#include <string>

//
// define a template function which applies the unary function object func
// to each element in the parameter pack elems.
// @pre func(std::forward<Elements>(elems)) must be well formed for each elems
// @returns void
//
template<class Function, class...Elements>
auto do_for_all(Function&& func, Elements&&...elems)
{
    using expand = int[];
    void(expand { 0, (func(elems), 0)... });
}

// a test structure which auto-initialises all members
struct X
{
    int i = 0;
    std::string s = "hello";
    double d = 4.4;
};

//
// The function foo
// introduces itself by writing intro to the console
// then performs the function object action on each of args
// @note all arguments are perfectly forwarded - no arguments are copied
//
template<class...Args>
auto foo(const std::string& intro, Args&&...args)
{
    std::cout << "introducing : " << intro << std::endl;
    auto action = [](auto&& arg)
    {
        std::cout << "performing action on: " << arg
        << " which is of type " << typeid(arg).name() << std::endl;
    };

    do_for_all(action, std::forward<Args>(args)...);
}

int main()
{
    // make an X
    auto x = X(); // make an X

    // foo it with the intro "my X"
    foo("my X", x.i, x.s, x.d);
}

示例输出:

introducing : my X
performing action on: 0 which is of type i
performing action on: hello which is of type NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
performing action on: 4.4 which is of type d
vjhs03f7

vjhs03f72#

您可以使用variadic templates(C++11起):

template <typename ... Type>
void foo(Type& ... args) {
    // do whatever you want, but this may be tricky
}

foo(X(1), X(2), X(3));

变量模板示例:min函数

这是我编写的代码,用于在计算多个值的最小值时消除对std::min的丑陋调用。

#include <type_traits>

namespace my {
    template <typename A, typename B>
    auto min(const A& a, const B& b) -> typename std::common_type<A, B>::type {
        return (a<b)?a:b;
    }

    template <typename A, typename B, typename ... T >
    auto min(const A& a, const B& b, const T& ... c) -> typename std::common_type<A, B, T ...>::type {
        const typename std::common_type<A, B, T ...>::type tmp = my::min(b, c ...);
        return (a<tmp)?a:tmp;
    }
}

// calculating minimum with my::min
my::min(3, 2, 3, 5, 23, 98); 

// doing the same with std::min
std::min(3, std::min(2, std::min(3, std::min(5, std::min(23, 98))))); // ugh, this is ugly!

这是棘手的部分:不能像vector s那样循环参数包,必须执行一些递归操作,如示例所示。

o4tp2gmn

o4tp2gmn3#

你可以写一个变量模板函数,把参数传递给std::initializer_list,然后遍历列表,例如:

#include <initializer_list>

template <typename ... Args>
void foo(Args && ... args) {
    std::initializer_list<X> as{std::forward<Args>(args)...};
    for (auto const & x : as)
        // Use x here
}

int main() {
    foo(1, 2, 3, 4, 5);
}

还要注意,你可能想要改变参数列表和初始化列表的类型以满足你的实际用例。例如,使用Args * ... argsstd::initializer_list<X *>或类似的。

相关问题