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

时间:2016-04-17 16:42:25

标签: c++ struct variadic-functions

我来自Swift背景,虽然我也知道一些C,但这是我第一次编写C ++代码。

在Swift中,可以编写一个带有任意数量参数的函数:

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

bar可以是任何类型(String,Bool,Struct,Enum等)。

我想知道在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;
}

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

3 个答案:

答案 0 :(得分:1)

这是众多方法中的一种。

您可以将整个程序复制/粘贴到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

答案 1 :(得分:0)

您可以使用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那样循环访问参数包。您将不得不进行一些递归,如示例所示。

答案 2 :(得分:0)

您可以编写一个可变参数模板函数,将参数传递给某些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 *>或类似内容。